import {ref, shallowReactive, watch, computed, type ComputedGetter} from 'vue' import {useRoute, useRouter} from 'vue-router' import {useRouteQuery} from '@vueuse/router' import TaskCollectionService, {getDefaultTaskFilterParams, type TaskFilterParams} from '@/services/taskCollection' import type {ITask} from '@/modelTypes/ITask' import {error} from '@/message' import type {IProject} from '@/modelTypes/IProject' import {useAuthStore} from '@/stores/auth' import type {IProjectView} from '@/modelTypes/IProjectView' export type Order = 'asc' | 'desc' | 'none' export interface SortBy { id?: Order index?: Order done?: Order title?: Order priority?: Order due_date?: Order start_date?: Order end_date?: Order percent_done?: Order created?: Order updated?: Order done_at?: Order, } const SORT_BY_DEFAULT: SortBy = { id: 'desc', } // This makes sure an id sort order is always sorted last. // When tasks would be sorted first by id and then by whatever else was specified, the id sort takes // precedence over everything else, making any other sort columns pretty useless. function formatSortOrder(sortBy, params) { let hasIdFilter = false const sortKeys = Object.keys(sortBy) for (const s of sortKeys) { if (s === 'id') { sortKeys.splice(s, 1) hasIdFilter = true break } } if (hasIdFilter) { sortKeys.push('id') } params.sort_by = sortKeys params.order_by = sortKeys.map(s => sortBy[s]) return params } /** * This mixin provides a base set of methods and properties to get tasks. */ export function useTaskList( projectIdGetter: ComputedGetter, projectViewIdGetter: ComputedGetter, sortByDefault: SortBy = SORT_BY_DEFAULT, ) { const projectId = computed(() => projectIdGetter()) const projectViewId = computed(() => projectViewIdGetter()) const params = ref({...getDefaultTaskFilterParams()}) const page = useRouteQuery('page', '1', { transform: Number }) const sortBy = ref({ ...sortByDefault }) const allParams = computed(() => { const loadParams = {...params.value} return formatSortOrder(sortBy.value, loadParams) }) watch( () => allParams.value, () => { // When parameters change, the page should always be the first page.value = 1 }, ) const authStore = useAuthStore() const getAllTasksParams = computed(() => { return [ { projectId: projectId.value, viewId: projectViewId.value, }, { ...allParams.value, filter_timezone: authStore.settings.timezone, }, page.value, ] }) const taskCollectionService = shallowReactive(new TaskCollectionService()) const loading = computed(() => taskCollectionService.loading) const totalPages = computed(() => taskCollectionService.totalPages) const tasks = ref([]) async function loadTasks(resetBeforeLoad: boolean = true) { if(resetBeforeLoad) { tasks.value = [] } try { tasks.value = await taskCollectionService.getAll(...getAllTasksParams.value) } catch (e) { error(e) } return tasks.value } const route = useRoute() watch(() => route.query, (query) => { const { page: pageQueryValue, s, filter, } = query if (s !== undefined) { params.value.s = s as string } if (pageQueryValue !== undefined) { page.value = Number(pageQueryValue) } if (filter !== undefined) { params.value.filter = filter } }, { immediate: true }) const router = useRouter() watch( () => [page.value, params.value.filter, params.value.s], () => { router.replace({ name: route.name, params: route.params, query: { page: page.value, filter: params.value.filter || undefined, s: params.value.s || undefined, }, }) }, { deep: true }, ) // Only listen for query path changes watch(() => JSON.stringify(getAllTasksParams.value), (newParams, oldParams) => { if (oldParams === newParams) { return } loadTasks() }, { immediate: true }) return { tasks, loading, totalPages, currentPage: page, loadTasks, params, sortByParam: sortBy, } }