Updated mobile view for field jobs
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { router } from "@inertiajs/vue3";
|
||||
|
||||
/**
|
||||
* Composable for infinite scroll with Inertia v2.
|
||||
*
|
||||
* @param {Function} getProp - () => the current paginator object from Inertia props
|
||||
* @param {string} propName - the prop key name to reload
|
||||
* @param {string} pageParam - query string parameter name for page number
|
||||
* @param {Function} getRouteUrl - () => current URL to reload
|
||||
*/
|
||||
export function useInfiniteList(getProp, propName, pageParam, getRouteUrl) {
|
||||
const items = ref([]);
|
||||
const currentPage = ref(1);
|
||||
const lastPage = ref(1);
|
||||
const isLoadingMore = ref(false);
|
||||
const sentinelRef = ref(null);
|
||||
let observer = null;
|
||||
|
||||
function syncFromProp() {
|
||||
const prop = getProp();
|
||||
if (!prop) return;
|
||||
lastPage.value = prop.last_page ?? 1;
|
||||
}
|
||||
|
||||
function appendFromProp() {
|
||||
const prop = getProp();
|
||||
if (!prop?.data) return;
|
||||
// append only new items (avoid duplicates by id)
|
||||
const existingIds = new Set(items.value.map((i) => i.id));
|
||||
const newItems = prop.data.filter((i) => !existingIds.has(i.id));
|
||||
items.value.push(...newItems);
|
||||
}
|
||||
|
||||
function reset(initialProp) {
|
||||
items.value = initialProp?.data ?? [];
|
||||
currentPage.value = initialProp?.current_page ?? 1;
|
||||
lastPage.value = initialProp?.last_page ?? 1;
|
||||
}
|
||||
|
||||
function loadMore() {
|
||||
if (isLoadingMore.value) return;
|
||||
if (currentPage.value >= lastPage.value) return;
|
||||
|
||||
const nextPage = currentPage.value + 1;
|
||||
isLoadingMore.value = true;
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.set(pageParam, nextPage);
|
||||
|
||||
router.reload({
|
||||
url: `${window.location.pathname}?${params.toString()}`,
|
||||
only: [propName],
|
||||
preserveScroll: true,
|
||||
preserveState: true,
|
||||
onSuccess: () => {
|
||||
appendFromProp();
|
||||
currentPage.value = nextPage;
|
||||
isLoadingMore.value = false;
|
||||
},
|
||||
onError: () => {
|
||||
isLoadingMore.value = false;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
loadMore();
|
||||
}
|
||||
},
|
||||
{ rootMargin: "200px" }
|
||||
);
|
||||
|
||||
if (sentinelRef.value) {
|
||||
observer.observe(sentinelRef.value);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
observer?.disconnect();
|
||||
});
|
||||
|
||||
return {
|
||||
items,
|
||||
currentPage,
|
||||
lastPage,
|
||||
isLoadingMore,
|
||||
sentinelRef,
|
||||
reset,
|
||||
syncFromProp,
|
||||
appendFromProp,
|
||||
loadMore,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user