Skip to content

Commit af0077e

Browse files
authored
feat: support null alias for task due clearing (#478)
1 parent 3ad6e6b commit af0077e

File tree

3 files changed

+67
-5
lines changed

3 files changed

+67
-5
lines changed

src/todoist-api.tasks.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,50 @@ describe('TodoistApi task endpoints', () => {
205205

206206
expect(response.isUncompletable).toBe(false)
207207
})
208+
209+
test('translates dueString null to "no date"', async () => {
210+
const returnedTask = {
211+
...DEFAULT_TASK,
212+
due: null,
213+
}
214+
215+
server.use(
216+
http.post(`${getSyncBaseUri()}${ENDPOINT_REST_TASKS}/123`, async ({ request }) => {
217+
const body = (await request.json()) as Record<string, unknown>
218+
expect(body.due_string).toBe('no date')
219+
return HttpResponse.json(returnedTask, { status: 200 })
220+
}),
221+
)
222+
const api = getTarget()
223+
224+
const response = await api.updateTask('123', {
225+
dueString: null,
226+
})
227+
228+
expect(response.due).toBeNull()
229+
})
230+
231+
test('keeps deadlineDate null in payload', async () => {
232+
const returnedTask = {
233+
...DEFAULT_TASK,
234+
deadline: null,
235+
}
236+
237+
server.use(
238+
http.post(`${getSyncBaseUri()}${ENDPOINT_REST_TASKS}/123`, async ({ request }) => {
239+
const body = (await request.json()) as Record<string, unknown>
240+
expect(body.deadline_date).toBeNull()
241+
return HttpResponse.json(returnedTask, { status: 200 })
242+
}),
243+
)
244+
const api = getTarget()
245+
246+
const response = await api.updateTask('123', {
247+
deadlineDate: null,
248+
})
249+
250+
expect(response.deadline).toBeNull()
251+
})
208252
})
209253

210254
describe('closeTask', () => {

src/todoist-api.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -588,18 +588,28 @@ export class TodoistApi {
588588
* Updates an existing task by its ID with the provided parameters.
589589
*
590590
* @param id - The unique identifier of the task to update.
591-
* @param args - Update parameters such as content, priority, or due date.
591+
* @param args - Update parameters such as content, priority, or due date. Pass
592+
* `dueString: null` (or `"no date"`) to clear the due date.
592593
* @param requestId - Optional custom identifier for the request.
593594
* @returns A promise that resolves to the updated task.
594595
*/
595596
async updateTask(id: string, args: UpdateTaskArgs, requestId?: string): Promise<Task> {
596597
z.string().parse(id)
597598

599+
// Translate SDK alias for due-date clearing to Todoist's accepted payload value.
600+
const normalizedArgs = args.dueString === null ? { ...args, dueString: 'no date' } : args
601+
598602
// Process content if both content and isUncompletable are provided
599603
const processedArgs =
600-
args.content && args.isUncompletable !== undefined
601-
? { ...args, content: processTaskContent(args.content, args.isUncompletable) }
602-
: args
604+
normalizedArgs.content && normalizedArgs.isUncompletable !== undefined
605+
? {
606+
...normalizedArgs,
607+
content: processTaskContent(
608+
normalizedArgs.content,
609+
normalizedArgs.isUncompletable,
610+
),
611+
}
612+
: normalizedArgs
603613

604614
const response = await request<Task>({
605615
httpMethod: 'POST',

src/types/requests.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,17 @@ export type UpdateTaskArgs = {
140140
description?: string
141141
labels?: string[]
142142
priority?: number
143-
dueString?: string
143+
/**
144+
* Natural language due date.
145+
* Use `"no date"` to clear a due date, or `null` as an SDK alias for the same behavior.
146+
*/
147+
dueString?: (string & {}) | 'no date' | null
144148
dueLang?: string | null
145149
assigneeId?: string | null
150+
/**
151+
* Deadline date in `YYYY-MM-DD` format.
152+
* Use `null` to clear a task deadline.
153+
*/
146154
deadlineDate?: string | null
147155
deadlineLang?: string | null
148156
isUncompletable?: boolean

0 commit comments

Comments
 (0)