Merge pull request #5865 from christianbeeznest/storm-22105

Course: Implement infinite scroll to load more than 30 courses - refs BT#22105
pull/5859/head
Nicolas Ducoulombier 10 months ago committed by GitHub
commit a23e4284b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 49
      assets/vue/graphql/queries/CourseRelUser.js
  2. 98
      assets/vue/views/user/courses/List.vue

@ -1,32 +1,37 @@
import gql from 'graphql-tag';
export const GET_COURSE_REL_USER = gql`
query getCourses($user: String!) {
courseRelUsers(user: $user) {
edges {
query getCourses($user: String!, $first: Int!, $after: String) {
courseRelUsers(user: $user, first: $first, after: $after) {
edges {
cursor
node {
course {
_id,
title,
illustrationUrl,
duration,
users(status: 1, first: 4) {
edges {
node {
course {
_id,
title,
illustrationUrl,
duration,
users(status: 1, first: 4) {
edges {
node {
id
status
user {
illustrationUrl,
username,
fullName
}
}
}
}
}
id
status
user {
illustrationUrl,
username,
fullName
}
}
}
}
}
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
`;

@ -4,7 +4,7 @@
<hr />
<div
v-if="isLoading"
v-if="isLoading && courses.length === 0"
class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
<Skeleton height="16rem" />
@ -23,10 +23,11 @@
</div>
<div
v-if="!isLoading && courses.length > 0"
v-if="courses.length > 0"
class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
<CourseCardList :courses="courses" />
<div ref="lastCourseRef"></div>
</div>
<EmptyState
v-else-if="!isLoading && 0 === courses.length"
@ -37,7 +38,7 @@
</template>
<script setup>
import { onMounted, computed } from "vue"
import { ref, watch, onMounted, nextTick } from "vue"
import { useQuery } from "@vue/apollo-composable"
import { useI18n } from "vue-i18n"
import { GET_COURSE_REL_USER } from "../../../graphql/queries/CourseRelUser.js"
@ -50,15 +51,96 @@ import { useSecurityStore } from "../../../store/securityStore"
const securityStore = useSecurityStore()
const { t } = useI18n()
const { result, loading, refetch } = useQuery(GET_COURSE_REL_USER, () => ({
const courses = ref([])
const isLoading = ref(false)
const endCursor = ref(null)
const hasMore = ref(true)
const lastCourseRef = ref(null)
const { result, fetchMore } = useQuery(GET_COURSE_REL_USER, {
user: securityStore.user["@id"],
}))
first: 30,
after: null,
})
watch(result, (newResult) => {
if (newResult?.courseRelUsers) {
const newCourses = newResult.courseRelUsers.edges.map(({ node }) => node.course)
const filteredCourses = newCourses.filter(
(newCourse) => !courses.value.some((existingCourse) => existingCourse._id === newCourse._id)
)
courses.value.push(...filteredCourses)
endCursor.value = newResult.courseRelUsers.pageInfo.endCursor
hasMore.value = newResult.courseRelUsers.pageInfo.hasNextPage
nextTick(() => {
if (lastCourseRef.value) {
observer.observe(lastCourseRef.value)
}
})
}
isLoading.value = false
})
const isLoading = computed(() => loading.value)
const loadMoreCourses = () => {
if (!hasMore.value || isLoading.value) return
isLoading.value = true
const courses = computed(() => result.value?.courseRelUsers.edges.map(({ node }) => node.course) ?? [])
fetchMore({
variables: {
user: securityStore.user["@id"],
first: 10,
after: endCursor.value,
},
updateQuery: (previousResult, {fetchMoreResult}) => {
if (!fetchMoreResult) return previousResult
const newCourses = fetchMoreResult.courseRelUsers.edges.map(({ node }) => node.course)
const filteredCourses = newCourses.filter(
(newCourse) => !courses.value.some((existingCourse) => existingCourse._id === newCourse._id)
)
courses.value.push(...filteredCourses)
endCursor.value = fetchMoreResult.courseRelUsers.pageInfo.endCursor
hasMore.value = fetchMoreResult.courseRelUsers.pageInfo.hasNextPage
return {
...previousResult,
courseRelUsers: {
...fetchMoreResult.courseRelUsers,
edges: [...previousResult.courseRelUsers.edges, ...fetchMoreResult.courseRelUsers.edges],
},
}
},
}).finally(() => {
isLoading.value = false
})
}
let observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadMoreCourses();
}
}, {
rootMargin: '300px',
})
onMounted(() => {
refetch()
courses.value = []
endCursor.value = null
hasMore.value = true
isLoading.value = false
if (observer) observer.disconnect()
observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadMoreCourses()
}
}, {
rootMargin: '300px',
})
loadMoreCourses()
})
</script>

Loading…
Cancel
Save