import { type Ref, ref } from 'vue' import debounce from 'lodash/debounce' import type ApiInterface from '../types/api-interface' import { ArkUiConstants } from './use-ark-ui' import { createQueryString } from '../utils' export interface PaginatedApiOptions { endpoint: string api?: ApiInterface params: Ref<{ [code: string]: string | string[] }> perPage: Ref paginationType?: string itemConverter?: (item: any) => any scrollPagination?: boolean responseItemsKey?: string responseTotalKey?: string orderingKey?: string requestPageKey?: string requestPerPageKey?: string paramsSerialization?: string } export default function usePaginatedApi(options: PaginatedApiOptions) { const defaultItemConverter = (item: any) => item const api = options.api || ArkUiConstants.api const paginationType = options.paginationType || ArkUiConstants.paginationType const itemConverter = options.itemConverter || defaultItemConverter const scrollPagination = options.scrollPagination || false const responseItemsKey = options.responseItemsKey || ArkUiConstants.responseItemsKey const responseTotalKey = options.responseTotalKey || ArkUiConstants.responseTotalKey const orderingKey = options.orderingKey || ArkUiConstants.orderingKey const requestPageKey = options.requestPageKey || ArkUiConstants.requestPageKey const requestPerPageKey = options.requestPerPageKey || ArkUiConstants.requestPerPageKey if (!api) throw new Error('API is not defined') const page = ref(1) const count = ref(0) const pages = ref(0) const sort = ref('') const sortDir = ref(true) const isLoading = ref(false) const items: Ref = ref([]) const actualRequestId = ref(0) const load = debounce(async (callback?: () => void) => { const queryParams: { [code: string]: string|string[]|number } = { ...options.params.value } if (paginationType === 'page') { queryParams[requestPageKey] = page.value queryParams[requestPerPageKey] = options.perPage.value } else { queryParams.limit = options.perPage.value queryParams.offset = (page.value - 1) * options.perPage.value } if (sort.value !== '') { queryParams[orderingKey] = (sortDir.value ? '' : '-') + sort.value } const requestId = Date.now() actualRequestId.value = requestId isLoading.value = true const response = options.paramsSerialization === 'custom' ? (await api.get(`${options.endpoint}${createQueryString(queryParams)}¶m_version=2`)).data : (await api.get(options.endpoint, { params: queryParams })).data if (requestId !== actualRequestId.value) { isLoading.value = false; return } count.value = response[responseTotalKey] const responseItems = response[responseItemsKey].map((i: any) => itemConverter(i)) items.value = scrollPagination ? [...items.value, ...responseItems] : responseItems pages.value = Math.ceil(count.value / options.perPage.value) isLoading.value = false if (callback) callback() }, 500) const reload = async () => { isLoading.value = true page.value = 1 items.value = [] await load() } const loadNext = async () => { if (isLoading.value || page.value >= pages.value) return page.value += 1 load() } const loadPrev = async () => { if (isLoading.value || page.value === 1) return page.value -= 1 load() } const loadPage = async (p: number) => { page.value = p load() } const setSort = (s: string) => { if (sort.value === '' || sort.value !== s) { sortDir.value = true sort.value = s } else { if (sortDir.value) { sortDir.value = false } else { sort.value = '' } } reload() } return { page, pages, count, isLoading, items, load, reload, loadNext, loadPrev, loadPage, setSort, sort, sortDir, } }