Tasks: ignore placeholder checklist completion dates from TickTick
All checks were successful
Deploy production / deploy (push) Successful in 2m34s

This commit is contained in:
2026-10-24 03:10:53 +00:00
parent 6a127de950
commit 1754ea9316
2 changed files with 12 additions and 3 deletions

View File

@@ -57,10 +57,13 @@ describe('ticktick mapping', () => {
completedTime: '2025-01-02T09:00:00.000+0000',
items: [
{ id: 'i1', title: 'milk', status: 1, completedTime: '2025-01-02T08:00:00.000+0000' },
{ id: 'i2', title: 'eggs', status: 0 }
{ id: 'i2', title: 'eggs', status: 0 },
{ id: 'i3', title: 'bread', status: 1, completedTime: 978307200000 }
]
} as Parameters<typeof mapTask>[0]);
expect(rows).toHaveLength(3);
expect(rows).toHaveLength(4);
// Placeholder completion (2001) falls back to the task's completion.
expect(rows[3].completedAt?.toISOString()).toBe('2025-01-02T09:00:00.000Z');
expect(rows[0]).toMatchObject({
title: 'Groceries',
notes: 'weekly',

View File

@@ -186,6 +186,12 @@ export function mapTask(t: TtTask): MappedRow[] {
updatedAt: modified,
ttSortOrder: t.sortOrder ?? 0
};
// Some old checklist items carry a placeholder completedTime (2001-01-01): ignore any
// completion before the task existed.
const itemDone = (v: string | number | undefined) => {
const d = ttDate(v);
return d && d.getTime() >= created.getTime() - 86_400_000 ? d : null;
};
const items = (t.items ?? []).map((i): MappedRow => {
// Checklist status: 0 open, 1 (or 2) checked. Unchecked items of a finished task
// follow the task (done → done, won't do → dropped) so they don't resurface as open.
@@ -205,7 +211,7 @@ export function mapTask(t: TtTask): MappedRow[] {
reminderAt: null,
recurrence: null,
completedAt: checked
? (ttDate(i.completedTime) ?? row.completedAt ?? modified)
? (itemDone(i.completedTime) ?? row.completedAt ?? modified)
: status === 'dropped'
? row.completedAt
: null,