store/resources/js/composables/useDataTableQuery.ts

86 lines
2.2 KiB
TypeScript

import { router } from '@inertiajs/vue3';
import { useDebounceFn } from '@vueuse/core';
import { ref, watch, type WatchSource } from 'vue';
import type { DataTableQuery, DataTableSort } from '@/types/data-table';
type UseDataTableQueryOptions = {
url: string;
initial: DataTableQuery;
filterKeys?: string[];
debounceMs?: number;
};
function buildParams(query: DataTableQuery, filterKeys: string[]): Record<string, string | undefined> {
const params: Record<string, string | undefined> = {
search: query.search || undefined,
sort: query.sort || undefined,
direction: query.direction || undefined,
};
for (const key of filterKeys) {
params[key] = query[key] || undefined;
}
return params;
}
export function useDataTableQuery(options: UseDataTableQueryOptions) {
const filterKeys = options.filterKeys ?? [];
const query = ref<DataTableQuery>({ ...options.initial });
const reload = useDebounceFn(() => {
router.get(options.url, buildParams(query.value, filterKeys), {
preserveState: true,
replace: true,
preserveScroll: true,
});
}, options.debounceMs ?? 300);
function setSearch(value: string): void {
query.value.search = value;
reload();
}
function setSort(sort: DataTableSort | null): void {
query.value.sort = sort?.column;
query.value.direction = sort?.direction;
reload();
}
function setFilter(key: string, value: string): void {
query.value[key] = value;
reload();
}
function resetFilters(): void {
for (const key of filterKeys) {
query.value[key] = '';
}
reload();
}
function syncFromServer(filters: DataTableQuery): void {
query.value = { ...filters };
}
return {
query,
setSearch,
setSort,
setFilter,
resetFilters,
reload,
syncFromServer,
};
}
export function useDataTableQuerySync(
filters: WatchSource<DataTableQuery>,
syncFromServer: (filters: DataTableQuery) => void,
): void {
watch(filters, (value) => {
syncFromServer(value);
});
}