2023-04-30 01:40:13 +00:00
|
|
|
import { useInfiniteScroll } from '@vueuse/core';
|
2024-06-06 13:16:59 +00:00
|
|
|
import { onMounted, ref, watch, type Ref, type UnwrapRef } from 'vue';
|
2023-04-30 01:40:13 +00:00
|
|
|
|
|
|
|
export async function usePaginate<T>(getSingle: (page: number) => Promise<T[]>): Promise<T[]> {
|
|
|
|
let hasMore = true;
|
|
|
|
let page = 1;
|
|
|
|
const result: T[] = [];
|
|
|
|
while (hasMore) {
|
|
|
|
const singleRes = await getSingle(page);
|
|
|
|
result.push(...singleRes);
|
|
|
|
hasMore = singleRes.length !== 0;
|
|
|
|
page += 1;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-12-16 09:29:13 +00:00
|
|
|
export function usePagination<T, S = unknown>(
|
|
|
|
_loadData: (page: number, arg: S) => Promise<T[] | null>,
|
2023-04-30 01:40:13 +00:00
|
|
|
isActive: () => boolean = () => true,
|
2024-04-29 19:33:45 +00:00
|
|
|
{
|
|
|
|
scrollElement: _scrollElement,
|
|
|
|
each: _each,
|
|
|
|
pageSize: _pageSize,
|
|
|
|
}: { scrollElement?: Ref<HTMLElement | null> | null; each?: S[]; pageSize?: number } = {},
|
2023-04-30 01:40:13 +00:00
|
|
|
) {
|
2024-04-29 19:33:45 +00:00
|
|
|
const scrollElement = _scrollElement === null ? null : ref(document.getElementById('scroll-component'));
|
2023-04-30 01:40:13 +00:00
|
|
|
const page = ref(1);
|
2024-04-29 19:33:45 +00:00
|
|
|
const pageSize = ref(_pageSize ?? 0);
|
2023-04-30 01:40:13 +00:00
|
|
|
const hasMore = ref(true);
|
|
|
|
const data = ref<T[]>([]) as Ref<T[]>;
|
|
|
|
const loading = ref(false);
|
2024-04-29 19:33:45 +00:00
|
|
|
const each = ref([...(_each ?? [])]);
|
2023-04-30 01:40:13 +00:00
|
|
|
|
|
|
|
async function loadData() {
|
2023-12-16 09:29:13 +00:00
|
|
|
if (loading.value === true || hasMore.value === false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-30 01:40:13 +00:00
|
|
|
loading.value = true;
|
2023-12-16 09:29:13 +00:00
|
|
|
const newData = (await _loadData(page.value, each.value?.[0] as S)) ?? [];
|
|
|
|
hasMore.value = newData.length >= pageSize.value && newData.length > 0;
|
|
|
|
if (newData.length > 0) {
|
|
|
|
data.value.push(...newData);
|
|
|
|
}
|
|
|
|
|
|
|
|
// last page and each has more
|
|
|
|
if (!hasMore.value && each.value.length > 0) {
|
|
|
|
// use next each element
|
|
|
|
each.value.shift();
|
|
|
|
page.value = 1;
|
2024-04-29 19:33:45 +00:00
|
|
|
pageSize.value = _pageSize ?? 0;
|
2023-12-16 09:29:13 +00:00
|
|
|
hasMore.value = each.value.length > 0;
|
|
|
|
if (hasMore.value) {
|
|
|
|
loading.value = false;
|
|
|
|
await loadData();
|
2023-04-30 01:40:13 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-16 09:29:13 +00:00
|
|
|
pageSize.value = newData.length;
|
2023-04-30 01:40:13 +00:00
|
|
|
loading.value = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
onMounted(loadData);
|
|
|
|
watch(page, loadData);
|
|
|
|
|
2023-12-16 09:29:13 +00:00
|
|
|
function nextPage() {
|
|
|
|
if (isActive() && !loading.value && hasMore.value) {
|
|
|
|
page.value += 1;
|
|
|
|
}
|
|
|
|
}
|
2023-04-30 01:40:13 +00:00
|
|
|
|
2024-04-29 19:33:45 +00:00
|
|
|
if (scrollElement !== null) {
|
|
|
|
useInfiniteScroll(scrollElement, nextPage, { distance: 10 });
|
|
|
|
}
|
2023-12-16 09:29:13 +00:00
|
|
|
|
|
|
|
async function resetPage() {
|
|
|
|
const _page = page.value;
|
|
|
|
|
2024-04-29 19:33:45 +00:00
|
|
|
page.value = 1;
|
|
|
|
pageSize.value = _pageSize ?? 0;
|
2023-12-16 09:29:13 +00:00
|
|
|
hasMore.value = true;
|
|
|
|
data.value = [];
|
2024-04-29 19:33:45 +00:00
|
|
|
loading.value = false;
|
|
|
|
each.value = [...(_each ?? [])] as UnwrapRef<S[]>;
|
2023-12-16 09:29:13 +00:00
|
|
|
|
|
|
|
if (_page === 1) {
|
|
|
|
// we need to reload manually as the page is already 1, so changing won't trigger watcher
|
|
|
|
await loadData();
|
2023-04-30 01:40:13 +00:00
|
|
|
}
|
2023-12-16 09:29:13 +00:00
|
|
|
}
|
2023-04-30 01:40:13 +00:00
|
|
|
|
2023-12-16 09:29:13 +00:00
|
|
|
return { resetPage, nextPage, data, hasMore, loading };
|
2023-04-30 01:40:13 +00:00
|
|
|
}
|