Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/TodoistApi.sections.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TodoistApi } from '.'
import { DEFAULT_AUTH_TOKEN, DEFAULT_REQUEST_ID, DEFAULT_SECTION } from './testUtils/testDefaults'
import { getSyncBaseUri, ENDPOINT_REST_SECTIONS } from './consts/endpoints'
import { setupRestClientMock } from './testUtils/mocks'
import { getSectionUrl } from './utils/urlHelpers'

function getTarget() {
return new TodoistApi(DEFAULT_AUTH_TOKEN)
Expand Down Expand Up @@ -32,6 +33,7 @@ describe('TodoistApi section endpoints', () => {
const section = await api.getSection('123')

expect(section).toEqual(DEFAULT_SECTION)
expect(section.url).toBe(getSectionUrl(section.id, section.name))
})
})

Expand Down Expand Up @@ -124,7 +126,12 @@ describe('TodoistApi section endpoints', () => {
})

test('returns success result from rest client', async () => {
const returnedSection = { ...DEFAULT_SECTION, ...DEFAULT_UPDATE_SECTION_ARGS }
const returnedSection = {
...DEFAULT_SECTION,
...DEFAULT_UPDATE_SECTION_ARGS,
id: '123',
url: getSectionUrl('123', 'a new name'),
}
setupRestClientMock(returnedSection, 204)
const api = getTarget()

Expand Down
4 changes: 3 additions & 1 deletion src/testUtils/testDefaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
RawComment,
PersonalProject,
} from '../types'
import { getProjectUrl, getTaskUrl } from '../utils/urlHelpers'
import { getProjectUrl, getTaskUrl, getSectionUrl } from '../utils/urlHelpers'

export const DEFAULT_TASK_ID = '1234'
export const DEFAULT_TASK_CONTENT = 'This is a task'
Expand Down Expand Up @@ -45,6 +45,7 @@ const DEFAULT_IS_COLLAPSED = false
// URL constants using the helper functions
const DEFAULT_TASK_URL = getTaskUrl(DEFAULT_TASK_ID, DEFAULT_TASK_CONTENT)
const DEFAULT_PROJECT_URL = getProjectUrl(DEFAULT_PROJECT_ID, DEFAULT_PROJECT_NAME)
const DEFAULT_SECTION_URL = getSectionUrl(DEFAULT_SECTION_ID, DEFAULT_SECTION_NAME)

export const DEFAULT_AUTH_TOKEN = 'AToken'
export const DEFAULT_REQUEST_ID = 'ARequestID'
Expand Down Expand Up @@ -174,6 +175,7 @@ export const DEFAULT_SECTION: Section = {
isArchived: false,
isDeleted: false,
isCollapsed: false,
url: DEFAULT_SECTION_URL,
}

export const INVALID_SECTION = {
Expand Down
35 changes: 21 additions & 14 deletions src/types/entities.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from 'zod'
import { getProjectUrl, getTaskUrl } from '../utils/urlHelpers'
import { getProjectUrl, getTaskUrl, getSectionUrl } from '../utils/urlHelpers'

export const DueDateSchema = z
.object({
Expand Down Expand Up @@ -148,19 +148,26 @@ export type WorkspaceProject = z.infer<typeof WorkspaceProjectSchema>
*/
export type ProjectViewStyle = 'list' | 'board' | 'calendar'

export const SectionSchema = z.object({
id: z.string(),
userId: z.string(),
projectId: z.string(),
addedAt: z.string(),
updatedAt: z.string(),
archivedAt: z.string().nullable(),
name: z.string(),
sectionOrder: z.number().int(),
isArchived: z.boolean(),
isDeleted: z.boolean(),
isCollapsed: z.boolean(),
})
export const SectionSchema = z
.object({
id: z.string(),
userId: z.string(),
projectId: z.string(),
addedAt: z.string(),
updatedAt: z.string(),
archivedAt: z.string().nullable(),
name: z.string(),
sectionOrder: z.number().int(),
isArchived: z.boolean(),
isDeleted: z.boolean(),
isCollapsed: z.boolean(),
})
.transform((data) => {
return {
...data,
url: getSectionUrl(data.id, data.name),
}
})
/**
* Represents a section in a Todoist project.
* @see https://todoist.com/api/v1/docs#tag/Sections
Expand Down
13 changes: 13 additions & 0 deletions src/utils/urlHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ export function getProjectUrl(projectId: string, name?: string): string {
return `${TODOIST_WEB_URI}/project/${path}`
}

/**
* Generate the URL for a given section.
*
* @param sectionId The ID of the section.
* @param name The name of the section.
* @returns The URL string for the section view.
*/
export function getSectionUrl(sectionId: string, name?: string): string {
const slug = name ? slugify(name) : undefined
const path = slug ? `${slug}-${sectionId}` : sectionId
return `${TODOIST_WEB_URI}/section/${path}`
}

/**
* Slugify function borrowed from Django.
*
Expand Down