Skip to content

feat: infinite scroll on course listing pages - #220

Merged
jobbykings merged 1 commit into
Epondia:mainfrom
ifygreg01-best:feat/infinite-scroll-course-listing
Jul 24, 2026
Merged

feat: infinite scroll on course listing pages#220
jobbykings merged 1 commit into
Epondia:mainfrom
ifygreg01-best:feat/infinite-scroll-course-listing

Conversation

@ifygreg01-best

@ifygreg01-best ifygreg01-best commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Replace traditional pagination with IntersectionObserver-based infinite scroll on the course listing page for a smoother browsing experience.

Changes

New hooks

  • useInfiniteScroll — attaches an IntersectionObserver to a sentinel element at the bottom of the list; fires onLoadMore when it enters the viewport (with 300 px pre-load margin). Guards against duplicate calls while a fetch is in flight.
  • useVirtualList — windowed rendering for large datasets; only renders the visible slice ± overscan buffer, reducing DOM nodes significantly.
  • useScrollRestoration — persists scroll position to sessionStorage, keyed by Next.js pathname or a custom key, and restores it on remount (e.g. navigating back to the listing).

New component

  • InfiniteScrollList — composes the three hooks above. Includes:
    • Loading spinner at the bottom during page fetches
    • Skeleton grid on initial load (no layout shift)
    • Empty state with optional clear-filters action
    • Error state with retry button (both full-page and inline for pagination failures)
    • End-of-list indicator once all results are loaded
    • Optional virtualized mode for datasets ≥ 40 items

Updated files

  • CourseGrid.tsx — removes the old "Load more" button; now drives InfiniteScrollList with inline search, sort, and category controls.
  • discoveryApi.ts — adds listCourses() with CourseListParams / CourseListResponse types supporting cursor-based pagination.
  • backend/src/routes/courses.js — adds GET /api/courses listing endpoint supporting both cursor (?cursor=<token>) and offset (?page=2) pagination. Validated via Joi + validateRequestSchema. Returns { items, total, page, limit, hasMore, nextCursor }.

What was tested

  • TypeScript: npx tsc --noEmit --skipLibCheck passes with zero errors on all new/modified files.
  • Backend syntax: node --check backend/src/routes/courses.js passes.
  • Manual checklist:
    • Scroll to bottom triggers next page automatically
    • Filter/sort changes reset to page 1 and refetch
    • Back-navigation restores scroll position
    • Error state shows retry button
    • Empty state shows clear-filters action
    • Skeleton grid shown on initial load (no layout shift)

Labels

area: frontend performance enhancement priority: medium

closes #196

- Add useInfiniteScroll hook (IntersectionObserver sentinel pattern)
- Add useVirtualList hook for windowed rendering on large datasets
- Add useScrollRestoration hook (sessionStorage, Next.js pathname-keyed)
- Add InfiniteScrollList component with loading spinner, empty state,
  error state with retry, and end-of-list indicator
- Rewrite CourseGrid to use InfiniteScrollList; remove Load More button
- Add GET /api/courses listing endpoint with cursor + offset pagination
- Add discoveryApi.listCourses() with CourseListParams/CourseListResponse

Closes #<issue-number>
@jobbykings
jobbykings merged commit ad47fb6 into Epondia:main Jul 24, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Frontend] Implement infinite scroll for course listings

2 participants