This repository has been archived on 2024-02-08. You can view files and clone it, but cannot push or open issues or pull requests.
frontend/src/composables/useRouteFilters.ts

74 lines
1.8 KiB
TypeScript

import {computed, ref, watch, type Ref} from 'vue'
import {useRouter, type RouteLocationNormalized, type RouteLocationRaw, type RouteRecordName} from 'vue-router'
import equal from 'fast-deep-equal/es6'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Filters = Record<string, any>
export function useRouteFilters<CurrentFilters extends Filters>(
route: Ref<RouteLocationNormalized>,
getDefaultFilters: (route: RouteLocationNormalized) => CurrentFilters,
routeToFilters: (route: RouteLocationNormalized) => CurrentFilters,
filtersToRoute: (filters: CurrentFilters) => RouteLocationRaw,
routeAllowList: RouteRecordName[] = [],
) {
const router = useRouter()
const filters = ref<CurrentFilters>(routeToFilters(route.value))
const routeFromFiltersFullPath = computed(() => router.resolve(filtersToRoute(filters.value)).fullPath)
watch(
route.value,
(route, oldRoute) => {
if (
route?.name !== oldRoute?.name ||
routeFromFiltersFullPath.value === route.fullPath ||
!routeAllowList.includes(route.name ?? '')
) {
return
}
filters.value = routeToFilters(route)
},
{
immediate: true, // set the filter from the initial route
},
)
watch(
filters,
async () => {
if (routeFromFiltersFullPath.value !== route.value.fullPath) {
await router.push(routeFromFiltersFullPath.value)
}
},
// only apply new route after all filters have changed in component cycle
{
deep: true,
flush: 'post',
},
)
const hasDefaultFilters = ref(false)
watch(
[filters, route],
([filters, route]) => {
hasDefaultFilters.value = equal(filters, getDefaultFilters(route))
},
{
deep: true,
immediate: true,
},
)
function setDefaultFilters() {
filters.value = getDefaultFilters(route.value)
}
return {
filters,
hasDefaultFilters,
setDefaultFilters,
}
}