Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | import { ref, shallowRef, type Ref, type ShallowRef } from 'vue' import type { Page } from '@/domain/pagination' export type PageParams = { cursor?: string | null; limit?: number } & Record<string, unknown> export type PageFetcher<T> = (params: PageParams) => Promise<Page<T>> export function usePagination<T>( fetchPage: PageFetcher<T>, options?: { pageSize?: number } ): { items: Ref<T[]> next: Ref<string | null> prev: Ref<string | null> total: Ref<number | null> loading: Ref<boolean> error: Ref<unknown> load: (baseParams?: PageParams) => Promise<void> loadNext: () => Promise<void> loadPrev: () => Promise<void> reset: () => void } { function makeItemsRef<U>(): ShallowRef<U[]> { return shallowRef<U[]>([]) } const items: Ref<T[]> = makeItemsRef<T>() const next: Ref<string | null> = ref<string | null>(null) const prev: Ref<string | null> = ref<string | null>(null) const total: Ref<number | null> = ref<number | null>(null) const loading: Ref<boolean> = ref<boolean>(false) const error: Ref<unknown> = ref<unknown>(null) const pageSize = options?.pageSize const lastBaseParams = ref<PageParams>({}) function assignFromPage(page: Page<T>) { items.value = page.items ?? [] next.value = page.next ?? null prev.value = page.prev ?? null total.value = page.total ?? null } async function load(baseParams: PageParams = {}) { loading.value = true error.value = null // keep base params without cursor; limit comes from options unless explicitly provided const { limit: _l, ...rest } = baseParams lastBaseParams.value = rest try { const params: PageParams = { ...rest } if (typeof _l === 'number') params.limit = _l else if (typeof pageSize === 'number') params.limit = pageSize const page = await fetchPage(params) assignFromPage(page) } catch (e) { error.value = e items.value = [] next.value = null prev.value = null total.value = null } finally { loading.value = false } } async function loadWithCursor(cursor: string | null) { if (!cursor) return loading.value = true error.value = null try { const params: PageParams = { ...lastBaseParams.value, cursor, } if (typeof pageSize === 'number') params.limit = pageSize const page = await fetchPage(params) assignFromPage(page) } catch (e) { error.value = e items.value = [] next.value = null prev.value = null total.value = null } finally { loading.value = false } } async function loadNext() { await loadWithCursor(next.value) } async function loadPrev() { await loadWithCursor(prev.value) } function reset() { items.value = [] next.value = null prev.value = null total.value = null loading.value = false error.value = null lastBaseParams.value = {} } return { items, next, prev, total, loading, error, load, loadNext, loadPrev, reset } } |