diff --git a/frontend/src/pages/SharedProjectPage.vue b/frontend/src/pages/SharedProjectPage.vue
index 83f7c2e..8e91dd6 100644
--- a/frontend/src/pages/SharedProjectPage.vue
+++ b/frontend/src/pages/SharedProjectPage.vue
@@ -146,24 +146,8 @@
-
-
-
- Page {{ page }} of {{ totalPages }}
-
-
+
+
{
return typeof value === 'string' && value ? value : ''
})
-const page = ref(1)
+const request = ref({ page: 1, append: false })
+const assets = ref([])
+const total = ref(0)
+const loadingMore = ref(false)
+const reachedEnd = ref(false)
+const sentinel = ref(null)
const preview = ref<{ asset: SharedAsset; url: string; downloadUrl?: string } | null>(null)
const downloadingAll = ref(false)
@@ -297,10 +287,22 @@ const assetsCall = useCall ({ ...scopeParams(), page: page.value, page_size: PAGE_SIZE }),
+ params: () => ({ ...scopeParams(), page: request.value.page, page_size: PAGE_SIZE }),
immediate: Boolean(token.value),
- refetch: true,
cacheKey: ['shared-assets', scopeId.value],
+ onSuccess: (data: SharedAssetsResponse) => {
+ total.value = data.total
+ if (request.value.append) {
+ const seen = new Set(assets.value.map((asset) => asset.name))
+ const fresh = data.assets.filter((asset) => !seen.has(asset.name))
+ assets.value = assets.value.concat(fresh)
+ reachedEnd.value = fresh.length === 0
+ } else {
+ assets.value = data.assets
+ reachedEnd.value = false
+ }
+ request.value.append = false
+ },
},
)
@@ -316,13 +318,22 @@ const downloadUrl = useCall({
immediate: false,
})
-const assets = computed(() => assetsCall.data?.assets ?? [])
-const total = computed(() => assetsCall.data?.total ?? 0)
-const totalPages = computed(() => assetsCall.data?.total_pages ?? 1)
const title = computed(() => info.data?.folder_name ?? info.data?.project_name ?? '')
+const hasMore = computed(() => !reachedEnd.value && assets.value.length < total.value)
usePageMeta(() => ({ title: title.value ? `${title.value} · VMS` : 'Shared · VMS' }))
+function loadMore() {
+ if (assetsCall.loading || loadingMore.value || !hasMore.value) return
+ loadingMore.value = true
+ request.value = { page: Math.floor(assets.value.length / PAGE_SIZE) + 1, append: true }
+ void assetsCall.reload().finally(() => {
+ loadingMore.value = false
+ })
+}
+
+useInfiniteScroll(sentinel, loadingMore, () => hasMore.value, loadMore)
+
function paramsFor(asset: SharedAsset): SharedAssetParams {
return { ...scopeParams(), asset_name: asset.name }
}