2022-09-03 14:51:20 +00:00
|
|
|
import type { RouteRecordName } from 'vue-router'
|
|
|
|
|
|
|
|
import { toRefs, useStorage, syncRef } from '@vueuse/core'
|
|
|
|
import { useRouteQuery } from '@vueuse/router'
|
|
|
|
import { useRoute } from 'vue-router'
|
2023-09-01 12:09:58 +00:00
|
|
|
import { watch, readonly } from 'vue'
|
2022-09-03 14:51:20 +00:00
|
|
|
|
|
|
|
export interface OrderingProps {
|
|
|
|
orderingConfigName?: RouteRecordName
|
|
|
|
}
|
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
export default <T extends string = string>(props: OrderingProps) => {
|
2022-09-03 14:51:20 +00:00
|
|
|
const route = useRoute()
|
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
interface Preferences {
|
|
|
|
orderingDirection: '-' | '+'
|
|
|
|
ordering: T
|
|
|
|
paginateBy: number
|
|
|
|
}
|
|
|
|
|
|
|
|
const preferences = useStorage<Preferences>(`route-preferences:${props.orderingConfigName?.toString() ?? route.name?.toString() ?? '*'}`, () => ({
|
2022-09-03 14:51:20 +00:00
|
|
|
orderingDirection: route.meta.orderingDirection ?? '-',
|
|
|
|
ordering: route.meta.ordering ?? 'creation_date',
|
|
|
|
paginateBy: route.meta.paginateBy ?? 50
|
2023-09-01 12:09:58 +00:00
|
|
|
}))
|
2022-09-03 14:51:20 +00:00
|
|
|
|
|
|
|
const {
|
2023-09-01 12:09:58 +00:00
|
|
|
orderingDirection: prefOrderingDirection,
|
|
|
|
paginateBy: prefPaginateBy,
|
|
|
|
ordering: prefOrdering
|
|
|
|
} = toRefs(preferences, {
|
|
|
|
replaceRef: false
|
2022-09-03 14:51:20 +00:00
|
|
|
})
|
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
const normalizeDirection = (direction: string) => direction === '+' ? '' : '-'
|
2022-09-03 14:51:20 +00:00
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
const queryOrdering = useRouteQuery(
|
|
|
|
'ordering',
|
|
|
|
normalizeDirection(prefOrderingDirection.value) + prefOrdering.value,
|
|
|
|
{ transform: (value) => value.trim() }
|
|
|
|
)
|
2022-09-03 14:51:20 +00:00
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
const queryPaginateBy = useRouteQuery('paginateBy', prefPaginateBy.value, {
|
|
|
|
transform: Number
|
2022-09-03 14:51:20 +00:00
|
|
|
})
|
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
// NOTE: Sync paginateBy in query string and preferences. We're using `flush: 'post'` to make sure that we sync after all updates are done
|
|
|
|
syncRef(queryPaginateBy, prefPaginateBy, {
|
|
|
|
flush: 'post'
|
2022-09-03 14:51:20 +00:00
|
|
|
})
|
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
// NOTE: Sync ordering from preferences to query string
|
|
|
|
watch([prefOrderingDirection, prefOrdering], () => {
|
|
|
|
queryOrdering.value = normalizeDirection(prefOrderingDirection.value) + prefOrdering.value.trim()
|
2022-09-03 14:51:20 +00:00
|
|
|
})
|
|
|
|
|
2023-09-01 12:09:58 +00:00
|
|
|
// NOTE: Sync ordering from query string to preferences
|
|
|
|
watch(queryOrdering, (ordering) => {
|
|
|
|
prefOrderingDirection.value = ordering[0] === '-' ? '-' : '+'
|
|
|
|
prefOrdering.value = ordering.replace(/^[+-]/, '')
|
|
|
|
}, { immediate: true })
|
|
|
|
|
|
|
|
// NOTE: We're using `flush: 'post'` to make sure that the `onOrderingUpdate` callback is called after all updates are done
|
|
|
|
const onOrderingUpdate = (fn: () => void) => watch(preferences, fn, {
|
|
|
|
flush: 'post'
|
|
|
|
})
|
2022-09-03 14:51:20 +00:00
|
|
|
|
|
|
|
return {
|
2023-09-01 12:09:58 +00:00
|
|
|
paginateBy: prefPaginateBy,
|
|
|
|
ordering: prefOrdering,
|
|
|
|
orderingDirection: prefOrderingDirection,
|
|
|
|
orderingString: readonly(queryOrdering),
|
2022-09-03 14:51:20 +00:00
|
|
|
onOrderingUpdate
|
|
|
|
}
|
|
|
|
}
|