feat: refine task and countdown interactions
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { applyMarkdownFormat, buildTaskRecurrencePayload, buildTaskRrule, classifyTaskForToday, defaultTaskDueAt, filterTasks, groupTaskTree, isSameTaskSortTier, mergeReorderedSubset, moveItemWithinScope, parseTaskRecurrence, parseTaskRrule, renderMarkdown, toDateTimeLocal } from './task-utils'
|
||||
import { applyMarkdownFormat, buildTaskDueDraft, buildTaskRecurrencePayload, buildTaskRrule, classifyTaskForToday, defaultTaskDueAt, filterTasks, groupTaskTree, isSameTaskSortTier, mergeReorderedSubset, moveItemWithinScope, parseTaskDueDraft, parseTaskRecurrence, parseTaskRrule, renderMarkdown, toDateTimeLocal } from './task-utils'
|
||||
|
||||
type SearchTask = {
|
||||
id: string
|
||||
@@ -136,4 +136,23 @@ describe('task utilities', () => {
|
||||
process.env.TZ = original
|
||||
expect(toDateTimeLocal(null)).toBe('')
|
||||
})
|
||||
|
||||
it('parses date-only and timed task deadlines without inventing a time', () => {
|
||||
const original = process.env.TZ
|
||||
process.env.TZ = 'Asia/Shanghai'
|
||||
expect(parseTaskDueDraft('2026-09-05T15:59:00Z', false)).toEqual({ date: '2026-09-05', hasTime: false, time: '12:00' })
|
||||
expect(parseTaskDueDraft('2026-09-05T12:30:00Z', true)).toEqual({ date: '2026-09-05', hasTime: true, time: '20:30' })
|
||||
expect(parseTaskDueDraft(null, true)).toEqual({ date: '', hasTime: false, time: '12:00' })
|
||||
process.env.TZ = original
|
||||
})
|
||||
|
||||
it('builds date-only, timed, toggled and cleared task deadlines in local time', () => {
|
||||
const original = process.env.TZ
|
||||
process.env.TZ = 'Asia/Shanghai'
|
||||
expect(buildTaskDueDraft({ date: '2026-09-05', hasTime: false, time: '08:15' })).toEqual({ due_at: '2026-09-05T15:59:00.000Z', due_has_time: false })
|
||||
expect(buildTaskDueDraft({ date: '2026-09-05', hasTime: true, time: '08:15' })).toEqual({ due_at: '2026-09-05T00:15:00.000Z', due_has_time: true })
|
||||
expect(buildTaskDueDraft({ date: '2026-09-05', hasTime: true, time: '' })).toEqual({ due_at: '2026-09-05T15:59:00.000Z', due_has_time: false })
|
||||
expect(buildTaskDueDraft({ date: '', hasTime: true, time: '08:15' })).toEqual({ due_at: null, due_has_time: false })
|
||||
process.env.TZ = original
|
||||
})
|
||||
})
|
||||
|
||||
@@ -217,6 +217,22 @@ export function defaultTaskDueAt(now = new Date()) {
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
export type TaskDueDraft = { date: string; hasTime: boolean; time: string }
|
||||
|
||||
export function parseTaskDueDraft(value: string | null | undefined, dueHasTime: boolean): TaskDueDraft {
|
||||
const local = toDateTimeLocal(value)
|
||||
if (!local) return { date: '', hasTime: false, time: '12:00' }
|
||||
const [date, time = '12:00'] = local.split('T')
|
||||
return { date, hasTime: dueHasTime, time: dueHasTime ? time : '12:00' }
|
||||
}
|
||||
|
||||
export function buildTaskDueDraft(draft: TaskDueDraft) {
|
||||
if (!draft.date) return { due_at: null, due_has_time: false }
|
||||
const hasTime = draft.hasTime && Boolean(draft.time)
|
||||
const local = `${draft.date}T${hasTime ? draft.time : '23:59'}`
|
||||
return { due_at: fromDateTimeLocal(local), due_has_time: hasTime }
|
||||
}
|
||||
|
||||
export function toDateTimeLocal(value: string | null | undefined) {
|
||||
if (!value) return ''
|
||||
const date = new Date(value)
|
||||
|
||||
Reference in New Issue
Block a user