diff --git a/src/composables/useRouteFilter.ts b/src/composables/useRouteFilter.ts new file mode 100644 index 000000000..a9daf1c5f --- /dev/null +++ b/src/composables/useRouteFilter.ts @@ -0,0 +1,43 @@ +import {reactive, watch, type Ref} from 'vue' +import {useRouter, type RouteLocationNormalized, type RouteLocationRaw} from 'vue-router' +import cloneDeep from 'lodash.clonedeep' + +export type Filter = Record + +export function useRouteFilter( + route: Ref, + routeToFilter: (route: RouteLocationNormalized) => F, + filterToRoute: (filter: F) => RouteLocationRaw, + ) { + const router = useRouter() + + const filters: F = reactive(routeToFilter(route.value)) + + watch(() => cloneDeep(route.value), (route, oldRoute) => { + if (route.name !== oldRoute.name) { + return + } + const filterFullPath = router.resolve(filterToRoute(filters)).fullPath + if (filterFullPath === route.fullPath) { + return + } + + Object.assign(filters, routeToFilter(route)) + }) + + watch( + filters, + async () => { + const newRouteFullPath = router.resolve(filterToRoute(filters)).fullPath + if (newRouteFullPath !== route.value.fullPath) { + await router.push(newRouteFullPath) + } + }, + // only apply new route after all filters have changed in component cycle + {flush: 'post'}, + ) + + return { + filters, + } +} \ No newline at end of file diff --git a/src/helpers/time/parseBooleanProp.ts b/src/helpers/time/parseBooleanProp.ts new file mode 100644 index 000000000..1407fe4e1 --- /dev/null +++ b/src/helpers/time/parseBooleanProp.ts @@ -0,0 +1,5 @@ +export function parseBooleanProp(booleanProp: string) { + return (booleanProp === 'false' || booleanProp === '0') + ? false + : Boolean(booleanProp) +} \ No newline at end of file diff --git a/src/helpers/time/parseDateProp.ts b/src/helpers/time/parseDateProp.ts new file mode 100644 index 000000000..4ee954f16 --- /dev/null +++ b/src/helpers/time/parseDateProp.ts @@ -0,0 +1,30 @@ +import type {DateISO} from "@/types/DateISO" +import type {DateKebab} from "@/types/DateKebab" + +export function parseDateProp(kebabDate: DateKebab | undefined): string | undefined { + try { + + if (!kebabDate) { + throw new Error('No value') + } + const dateValues = kebabDate.split('-') + const [, monthString, dateString] = dateValues + const [year, month, date] = dateValues.map(val => Number(val)) + const dateValuesAreValid = ( + !Number.isNaN(year) && + monthString.length >= 1 && monthString.length <= 2 && + !Number.isNaN(month) && + month >= 1 && month <= 12 && + dateString.length >= 1 && dateString.length <= 31 && + !Number.isNaN(date) && + date >= 1 && date <= 31 + ) + if (!dateValuesAreValid) { + throw new Error('Invalid date values') + } + return new Date(year, month, date).toISOString() as DateISO + } catch(e) { + // ignore nonsense route queries + return + } +} \ No newline at end of file diff --git a/src/types/DateISO.ts b/src/types/DateISO.ts index 77c1759b4..0db782318 100644 --- a/src/types/DateISO.ts +++ b/src/types/DateISO.ts @@ -2,6 +2,6 @@ * Returns a date as a string value in ISO format. * same format as `new Date().toISOString()` */ -export type DateISO = string +export type DateISO = T new Date().toISOString() \ No newline at end of file diff --git a/src/views/list/ListGantt.vue b/src/views/list/ListGantt.vue index 06913b97d..a7bd1fe44 100644 --- a/src/views/list/ListGantt.vue +++ b/src/views/list/ListGantt.vue @@ -39,12 +39,11 @@