Skip to content

Commit 3286250

Browse files
committed
add infinite scroll to time page
1 parent efd2fa4 commit 3286250

File tree

1 file changed

+47
-5
lines changed

1 file changed

+47
-5
lines changed

src/renderer/src/components/MainTimeEntryTable.vue

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
import { useQuery } from '@tanstack/vue-query'
2+
import { useQuery, useInfiniteQuery } from '@tanstack/vue-query'
33
import { type Component, computed, nextTick, onMounted, ref, watch, watchEffect } from 'vue'
44
55
import {
@@ -14,6 +14,7 @@ import {
1414
emptyTimeEntry,
1515
getAllTimeEntries,
1616
getCurrentTimeEntry,
17+
getTimeEntriesPage,
1718
useTimeEntryCreateMutation,
1819
useTimeEntryDeleteMutation,
1920
useTimeEntryStopMutation,
@@ -39,7 +40,7 @@ import { LoadingSpinner } from '@solidtime/ui'
3940
import { useLiveTimer } from '../utils/liveTimer.ts'
4041
import { ClockIcon } from '@heroicons/vue/20/solid'
4142
import { CardTitle } from '@solidtime/ui'
42-
import { useStorage } from '@vueuse/core'
43+
import { useStorage, useElementVisibility } from '@vueuse/core'
4344
import { currentMembershipId, useMyMemberships } from '../utils/myMemberships.ts'
4445
import { getAllClients, useClientCreateMutation } from '../utils/clients.ts'
4546
import { dayjs } from '../utils/dayjs.ts'
@@ -58,12 +59,30 @@ watch(currentOrganizationId, () => {
5859
selectedTimeEntries.value = []
5960
})
6061
61-
const { data: timeEntriesResponse } = useQuery({
62+
const {
63+
data: timeEntriesInfiniteData,
64+
fetchNextPage,
65+
hasNextPage,
66+
isFetchingNextPage,
67+
} = useInfiniteQuery({
6268
queryKey: ['timeEntries', currentOrganizationId],
63-
queryFn: () => getAllTimeEntries(currentOrganizationId.value, currentMembershipId.value),
69+
queryFn: ({ pageParam }) =>
70+
getTimeEntriesPage(currentOrganizationId.value, currentMembershipId.value, pageParam),
71+
getNextPageParam: (lastPage) => {
72+
if (lastPage?.data && lastPage.data.length > 0) {
73+
const lastTimeEntry = lastPage.data[lastPage.data.length - 1]
74+
return lastTimeEntry.start
75+
}
76+
return undefined
77+
},
6478
enabled: currentOrganizationLoaded,
79+
initialPageParam: undefined as string | undefined,
80+
})
81+
82+
const timeEntries = computed(() => {
83+
if (!timeEntriesInfiniteData.value) return undefined
84+
return timeEntriesInfiniteData.value.pages.flatMap((page) => page.data)
6585
})
66-
const timeEntries = computed(() => timeEntriesResponse.value?.data)
6786
6887
const { data: currentTimeEntryResponse, isError: currentTimeEntryResponseIsError } = useQuery({
6988
queryKey: ['currentTimeEntry'],
@@ -321,6 +340,16 @@ const canCreateProjects = computed(() => {
321340
})
322341
323342
const showManualTimeEntryModal = ref(false)
343+
344+
// Infinite scroll
345+
const loadMoreContainer = ref<HTMLDivElement | null>(null)
346+
const isLoadMoreVisible = useElementVisibility(loadMoreContainer)
347+
348+
watch(isLoadMoreVisible, async (isVisible) => {
349+
if (isVisible && hasNextPage.value && !isFetchingNextPage.value) {
350+
await fetchNextPage()
351+
}
352+
})
324353
</script>
325354

326355
<template>
@@ -440,6 +469,19 @@ const showManualTimeEntryModal = ref(false)
440469
<h3 class="text-white font-semibold">No time entries found</h3>
441470
<p class="pb-5 text-muted">Create your first time entry now!</p>
442471
</div>
472+
<div ref="loadMoreContainer">
473+
<div
474+
v-if="isFetchingNextPage"
475+
class="flex justify-center items-center py-5 text-white font-medium">
476+
<LoadingSpinner class="ml-0 mr-0"></LoadingSpinner>
477+
<span class="ml-2"> Loading more time entries... </span>
478+
</div>
479+
<div
480+
v-else-if="!hasNextPage && timeEntries && timeEntries.length > 0"
481+
class="flex justify-center items-center py-5 text-muted font-medium">
482+
All time entries are loaded!
483+
</div>
484+
</div>
443485
</div>
444486
</div>
445487
<div v-else class="flex items-center justify-center h-full">

0 commit comments

Comments
 (0)