diff --git a/src/composables/useRouteFilter.ts b/src/composables/useRouteFilter.ts index a9daf1c5f..abcd1f03a 100644 --- a/src/composables/useRouteFilter.ts +++ b/src/composables/useRouteFilter.ts @@ -1,4 +1,4 @@ -import {reactive, watch, type Ref} from 'vue' +import {computed, ref, watch, type Ref} from 'vue' import {useRouter, type RouteLocationNormalized, type RouteLocationRaw} from 'vue-router' import cloneDeep from 'lodash.clonedeep' @@ -11,26 +11,26 @@ export function useRouteFilter( ) { const router = useRouter() - const filters: F = reactive(routeToFilter(route.value)) + const filters = ref(routeToFilter(route.value)) + + const routeFromFiltersFullPath = computed(() => router.resolve(filterToRoute(filters.value)).fullPath) watch(() => cloneDeep(route.value), (route, oldRoute) => { - if (route.name !== oldRoute.name) { - return - } - const filterFullPath = router.resolve(filterToRoute(filters)).fullPath - if (filterFullPath === route.fullPath) { + if ( + route.name !== oldRoute.name || + routeFromFiltersFullPath.value === route.fullPath + ) { return } - Object.assign(filters, routeToFilter(route)) + filters.value = routeToFilter(route) }) watch( filters, async () => { - const newRouteFullPath = router.resolve(filterToRoute(filters)).fullPath - if (newRouteFullPath !== route.value.fullPath) { - await router.push(newRouteFullPath) + if (routeFromFiltersFullPath.value !== route.value.fullPath) { + await router.push(routeFromFiltersFullPath.value) } }, // only apply new route after all filters have changed in component cycle diff --git a/src/views/list/ListGantt.vue b/src/views/list/ListGantt.vue index 7eb5ae737..253a7ffdb 100644 --- a/src/views/list/ListGantt.vue +++ b/src/views/list/ListGantt.vue @@ -87,7 +87,7 @@ const defaultTaskEndDate: DateISO = new Date(today.getFullYear(), today.getMonth async function addGanttTask(title: ITask['title']) { return await addTask({ title, - listId: filters.listId, + listId: filters.value.listId, startDate: defaultTaskStartDate, endDate: defaultTaskEndDate, }) @@ -96,8 +96,8 @@ async function addGanttTask(title: ITask['title']) { const flatPickerEl = ref(null) const flatPickerDateRange = computed({ get: () => ([ - new Date(filters.dateFrom), - new Date(filters.dateTo), + new Date(filters.value.dateFrom), + new Date(filters.value.dateTo), ]), set(newVal) { const [dateFrom, dateTo] = newVal.map((date) => date?.toISOString()) @@ -105,11 +105,11 @@ const flatPickerDateRange = computed({ // only set after whole range has been selected if (!dateTo) return - Object.assign(filters, {dateFrom, dateTo}) + Object.assign(filters.value, {dateFrom, dateTo}) }, }) -const initialDateRange = [filters.dateFrom, filters.dateTo] +const initialDateRange = [filters.value.dateFrom, filters.value.dateTo] const {t} = useI18n({useScope: 'global'}) const authStore = useAuthStore() diff --git a/src/views/list/helpers/useGanttFilter.ts b/src/views/list/helpers/useGanttFilter.ts index 9268c903c..87286ff03 100644 --- a/src/views/list/helpers/useGanttFilter.ts +++ b/src/views/list/helpers/useGanttFilter.ts @@ -36,7 +36,8 @@ function getDefaultDateTo() { return new Date(now.getFullYear(), now.getMonth(), now.getDate() + DEFAULT_DATETO_DAY_OFFSET).toISOString() } -function routeToFilter(route: RouteLocationNormalized): GanttFilter { +// FIXME: use zod for this +function ganttRouteToFilter(route: RouteLocationNormalized): GanttFilter { return { listId: Number(route.params.listId as string), dateFrom: parseDateProp(route.query.dateFrom as DateKebab) || getDefaultDateFrom(), @@ -45,7 +46,8 @@ function routeToFilter(route: RouteLocationNormalized): GanttFilter { } } -function filterToRoute(filters: GanttFilter): RouteLocationRaw { +// FIXME: use zod for this +function ganttFilterToRoute(filters: GanttFilter): RouteLocationRaw { let query: Record = {} if ( filters.dateFrom !== getDefaultDateFrom() || @@ -80,8 +82,8 @@ function ganttFiltersToApiParams(filters: GanttFilter): GetAllTasksParams { } } -export function useGanttFilter(route: Ref) { - const {filters} = useRouteFilter(route, routeToFilter, filterToRoute) +export function useGanttFilter(route: Ref): ReturnType & ReturnType { + const {filters} = useRouteFilter(route, ganttRouteToFilter, ganttFilterToRoute) const { tasks, diff --git a/src/views/list/helpers/useGanttTaskList.ts b/src/views/list/helpers/useGanttTaskList.ts index 2ba854273..55faf29d0 100644 --- a/src/views/list/helpers/useGanttTaskList.ts +++ b/src/views/list/helpers/useGanttTaskList.ts @@ -1,10 +1,10 @@ -import {computed, ref, shallowReactive, watchEffect} from 'vue' +import {computed, ref, shallowReactive, watch, type Ref} from 'vue' import cloneDeep from 'lodash.clonedeep' import type {Filter} from '@/composables/useRouteFilter' import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask' -import TaskCollectionService, { type GetAllTasksParams } from '@/services/taskCollection' +import TaskCollectionService, {type GetAllTasksParams} from '@/services/taskCollection' import TaskService from '@/services/task' import TaskModel from '@/models/task' @@ -12,7 +12,7 @@ import {error, success} from '@/message' // FIXME: unify with general `useTaskList` export function useGanttTaskList( - filters: F, + filters: Ref, filterToApiParams: (filters: F) => GetAllTasksParams, options: { loadAll?: boolean, @@ -27,7 +27,7 @@ export function useGanttTaskList( const tasks = ref>(new Map()) async function fetchTasks(params: GetAllTasksParams, page = 1): Promise { - const tasks = await taskCollectionService.getAll({listId: filters.listId}, params, page) as ITask[] + const tasks = await taskCollectionService.getAll({listId: filters.value.listId}, params, page) as ITask[] if (options.loadAll && page < taskCollectionService.totalPages) { const nextTasks = await fetchTasks(params, page + 1) return tasks.concat(nextTasks) @@ -35,15 +35,26 @@ export function useGanttTaskList( return tasks } - async function loadTasks(filters: F) { - const params: GetAllTasksParams = filterToApiParams(filters) + /** + * Load and assign new tasks + * Normally there is no need to trigger this manually + */ + async function loadTasks() { + const params: GetAllTasksParams = filterToApiParams(filters.value) const loadedTasks = await fetchTasks(params) tasks.value = new Map() loadedTasks.forEach(t => tasks.value.set(t.id, t)) } - watchEffect(() => loadTasks(filters)) + /** + * Load tasks when filters change + */ + watch( + filters, + () => loadTasks(), + {immediate: true, deep: true}, + ) async function addTask(task: Partial) { const newTask = await taskService.create(new TaskModel({...task})) @@ -83,6 +94,8 @@ export function useGanttTaskList( tasks, isLoading, + loadTasks, + addTask, updateTask, }