feat: use ref for filters

This commit is contained in:
Dominik Pschenitschni 2022-10-19 16:48:26 +02:00
parent 94e2a7d001
commit 9235fabaa9
Signed by: dpschen
GPG Key ID: B257AC0149F43A77
4 changed files with 42 additions and 27 deletions

View File

@ -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 {useRouter, type RouteLocationNormalized, type RouteLocationRaw} from 'vue-router'
import cloneDeep from 'lodash.clonedeep' import cloneDeep from 'lodash.clonedeep'
@ -11,26 +11,26 @@ export function useRouteFilter<F extends Filter = Filter>(
) { ) {
const router = useRouter() const router = useRouter()
const filters: F = reactive(routeToFilter(route.value)) const filters = ref<F>(routeToFilter(route.value))
const routeFromFiltersFullPath = computed(() => router.resolve(filterToRoute(filters.value)).fullPath)
watch(() => cloneDeep(route.value), (route, oldRoute) => { watch(() => cloneDeep(route.value), (route, oldRoute) => {
if (route.name !== oldRoute.name) { if (
return route.name !== oldRoute.name ||
} routeFromFiltersFullPath.value === route.fullPath
const filterFullPath = router.resolve(filterToRoute(filters)).fullPath ) {
if (filterFullPath === route.fullPath) {
return return
} }
Object.assign(filters, routeToFilter(route)) filters.value = routeToFilter(route)
}) })
watch( watch(
filters, filters,
async () => { async () => {
const newRouteFullPath = router.resolve(filterToRoute(filters)).fullPath if (routeFromFiltersFullPath.value !== route.value.fullPath) {
if (newRouteFullPath !== route.value.fullPath) { await router.push(routeFromFiltersFullPath.value)
await router.push(newRouteFullPath)
} }
}, },
// only apply new route after all filters have changed in component cycle // only apply new route after all filters have changed in component cycle

View File

@ -87,7 +87,7 @@ const defaultTaskEndDate: DateISO = new Date(today.getFullYear(), today.getMonth
async function addGanttTask(title: ITask['title']) { async function addGanttTask(title: ITask['title']) {
return await addTask({ return await addTask({
title, title,
listId: filters.listId, listId: filters.value.listId,
startDate: defaultTaskStartDate, startDate: defaultTaskStartDate,
endDate: defaultTaskEndDate, endDate: defaultTaskEndDate,
}) })
@ -96,8 +96,8 @@ async function addGanttTask(title: ITask['title']) {
const flatPickerEl = ref<typeof Foo | null>(null) const flatPickerEl = ref<typeof Foo | null>(null)
const flatPickerDateRange = computed<Date[]>({ const flatPickerDateRange = computed<Date[]>({
get: () => ([ get: () => ([
new Date(filters.dateFrom), new Date(filters.value.dateFrom),
new Date(filters.dateTo), new Date(filters.value.dateTo),
]), ]),
set(newVal) { set(newVal) {
const [dateFrom, dateTo] = newVal.map((date) => date?.toISOString()) const [dateFrom, dateTo] = newVal.map((date) => date?.toISOString())
@ -105,11 +105,11 @@ const flatPickerDateRange = computed<Date[]>({
// only set after whole range has been selected // only set after whole range has been selected
if (!dateTo) return 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 {t} = useI18n({useScope: 'global'})
const authStore = useAuthStore() const authStore = useAuthStore()

View File

@ -36,7 +36,8 @@ function getDefaultDateTo() {
return new Date(now.getFullYear(), now.getMonth(), now.getDate() + DEFAULT_DATETO_DAY_OFFSET).toISOString() 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 { return {
listId: Number(route.params.listId as string), listId: Number(route.params.listId as string),
dateFrom: parseDateProp(route.query.dateFrom as DateKebab) || getDefaultDateFrom(), 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<string, string> = {} let query: Record<string, string> = {}
if ( if (
filters.dateFrom !== getDefaultDateFrom() || filters.dateFrom !== getDefaultDateFrom() ||
@ -80,8 +82,8 @@ function ganttFiltersToApiParams(filters: GanttFilter): GetAllTasksParams {
} }
} }
export function useGanttFilter(route: Ref<RouteLocationNormalized>) { export function useGanttFilter(route: Ref<RouteLocationNormalized>): ReturnType<typeof useRouteFilter> & ReturnType<typeof useGanttTaskList> {
const {filters} = useRouteFilter<GanttFilter>(route, routeToFilter, filterToRoute) const {filters} = useRouteFilter<GanttFilter>(route, ganttRouteToFilter, ganttFilterToRoute)
const { const {
tasks, tasks,

View File

@ -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 cloneDeep from 'lodash.clonedeep'
import type {Filter} from '@/composables/useRouteFilter' import type {Filter} from '@/composables/useRouteFilter'
import type {ITask, ITaskPartialWithId} from '@/modelTypes/ITask' 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 TaskService from '@/services/task'
import TaskModel from '@/models/task' import TaskModel from '@/models/task'
@ -12,7 +12,7 @@ import {error, success} from '@/message'
// FIXME: unify with general `useTaskList` // FIXME: unify with general `useTaskList`
export function useGanttTaskList<F extends Filter>( export function useGanttTaskList<F extends Filter>(
filters: F, filters: Ref<F>,
filterToApiParams: (filters: F) => GetAllTasksParams, filterToApiParams: (filters: F) => GetAllTasksParams,
options: { options: {
loadAll?: boolean, loadAll?: boolean,
@ -27,7 +27,7 @@ export function useGanttTaskList<F extends Filter>(
const tasks = ref<Map<ITask['id'], ITask>>(new Map()) const tasks = ref<Map<ITask['id'], ITask>>(new Map())
async function fetchTasks(params: GetAllTasksParams, page = 1): Promise<ITask[]> { async function fetchTasks(params: GetAllTasksParams, page = 1): Promise<ITask[]> {
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) { if (options.loadAll && page < taskCollectionService.totalPages) {
const nextTasks = await fetchTasks(params, page + 1) const nextTasks = await fetchTasks(params, page + 1)
return tasks.concat(nextTasks) return tasks.concat(nextTasks)
@ -35,15 +35,26 @@ export function useGanttTaskList<F extends Filter>(
return tasks 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) const loadedTasks = await fetchTasks(params)
tasks.value = new Map() tasks.value = new Map()
loadedTasks.forEach(t => tasks.value.set(t.id, t)) 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<ITask>) { async function addTask(task: Partial<ITask>) {
const newTask = await taskService.create(new TaskModel({...task})) const newTask = await taskService.create(new TaskModel({...task}))
@ -83,6 +94,8 @@ export function useGanttTaskList<F extends Filter>(
tasks, tasks,
isLoading, isLoading,
loadTasks,
addTask, addTask,
updateTask, updateTask,
} }