Skip to content

Commit

Permalink
infinite scroll
Browse files Browse the repository at this point in the history
  • Loading branch information
pblvrt committed Aug 8, 2024
1 parent 0b77b3a commit 4bd30f7
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 35 deletions.
60 changes: 46 additions & 14 deletions packages/app/app/[organization]/videos/components/ArchiveVideos.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { fetchAllSessions } from '@/lib/data';
'use client';
import Videos from '@/components/misc/Videos';
import { FileQuestion } from 'lucide-react';
import { FileQuestion, VideoOff } from 'lucide-react';
import Pagination from './pagination';
import { useEffect, useState } from 'react';
import { IExtendedSession, IPagination } from '@/lib/types';
import { fetchAllSessions } from '@/lib/services/sessionService';
import ArchiveVideoSkeleton from '../../../[organization]/livestream/components/ArchiveVideosSkeleton';

const ArchiveVideos = async ({
const ArchiveVideos = ({
organizationSlug,
event,
searchQuery,
Expand All @@ -14,17 +18,41 @@ const ArchiveVideos = async ({
searchQuery?: string;
page?: number;
}) => {
const videos = await fetchAllSessions({
organizationSlug,
event: event,
limit: 12,
onlyVideos: true,
published: true,
searchQuery,
page: Number(page || 1),
const [isLoading, setIsLoading] = useState(false);
const [videos, setVideos] = useState<IExtendedSession[]>([]);
const [currentSearchQuery, setCurrentSearchQuery] = useState('');
const [pagination, setPagination] = useState<IPagination>({
currentPage: 1,
totalPages: 0,
totalItems: 0,
limit: 0,
});
useEffect(() => {
setIsLoading(true);
fetchAllSessions({
organizationSlug,
event: event,
limit: 12,
onlyVideos: true,
published: true,
searchQuery,
page: Number(page || 1),
})
.then((data) => {
if (searchQuery && searchQuery !== currentSearchQuery) {
setVideos(data.sessions);
setCurrentSearchQuery(searchQuery);
} else {
setVideos([...videos, ...data.sessions]);
}
setPagination(data.pagination);
})
.finally(() => {
setIsLoading(false);
});
}, [organizationSlug, event, searchQuery, page]);

if (videos.pagination.totalItems === 0) {
if (Videos.length === 0) {
return (
<div className="mt-10 flex h-full w-full flex-col items-center justify-center">
<FileQuestion size={65} />
Expand All @@ -37,8 +65,12 @@ const ArchiveVideos = async ({

return (
<>
<Videos OrganizationSlug={organizationSlug} videos={videos.sessions} />
<Pagination {...videos.pagination} />
{isLoading ? (
<ArchiveVideoSkeleton />
) : (
<Videos OrganizationSlug={organizationSlug} videos={videos} />
)}
<Pagination {...pagination} />
</>
);
};
Expand Down
33 changes: 33 additions & 0 deletions packages/app/app/[organization]/videos/components/pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,45 @@ import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import React, { useState } from 'react';
import { LuArrowLeft, LuArrowRight } from 'react-icons/lu';
import { useEffect } from 'react';

const Pagination = (props: IPagination) => {
const [jumpPage, setJumpPage] = useState(props.currentPage);
const { handleTermChange, searchParams } = useSearchParams();
const currentPage = Number(searchParams.get('page')) || 1;

// trigger when reaching bottom of the page
useEffect(() => {
console.log(
window.innerHeight,
document.documentElement.scrollTop,
document.documentElement.offsetHeight
);
const handleScroll = () => {
console.log(
window.innerHeight + document.documentElement.scrollTop,
document.documentElement.offsetHeight
);

if (
window.innerHeight + document.documentElement.scrollTop + 1 <
document.documentElement.offsetHeight
) {
return;
}
if (currentPage < props.totalPages) {
handleTermChange([
{
key: 'page',
value: (currentPage + 1).toString(),
},
]);
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [currentPage, props.totalPages, handleTermChange]);

return (
<div className="flex flex-row items-center justify-center p-2">
<div className="flex items-center gap-3">
Expand Down
3 changes: 2 additions & 1 deletion packages/app/components/misc/Videos.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use client';
import { IExtendedSession } from '@/lib/types';
import VideoCardWithMenu from './VideoCard/VideoCardWithMenu';
import { Suspense } from 'react';
import { Card, CardHeader, CardDescription } from '@/components/ui/card';
export default async function VideoGrid({
export default function VideoGrid({
videos,
OrganizationSlug,
maxVideos,
Expand Down
1 change: 1 addition & 0 deletions packages/app/lib/actions/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IEvent } from 'streameth-new-server/src/interfaces/event.interface';
import { revalidatePath } from 'next/cache';
import GoogleSheetService from '@/lib/services/googleSheetService';
import GoogleDriveService from '@/lib/services/googleDriveService';

export const createEventAction = async ({ event }: { event: IEvent }) => {
const authToken = cookies().get('user-session')?.value;
if (!authToken) {
Expand Down
7 changes: 5 additions & 2 deletions packages/app/lib/hooks/useSearchParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface ITerm {
}
const useSearchParams = () => {
const pathname = usePathname();
const { replace } = useRouter();
const { push } = useRouter();
const searchParams = useNextSearchParams();

function handleTermChange(terms: ITerm[]) {
Expand All @@ -21,9 +21,12 @@ const useSearchParams = () => {
} else {
params.delete(term.key);
}
replace(`${pathname}?${params.toString()}`);
push(`${pathname}?${params.toString()}`, {
scroll: false,
});
}
}

return {
searchParams,
handleTermChange,
Expand Down
11 changes: 3 additions & 8 deletions packages/app/lib/services/eventService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,11 @@ export async function fetchEvents({
return [];
}
const response = await fetch(
`${apiUrl()}/events?organizationId=${organization._id}`,
{ cache: 'no-store' }
`${apiUrl()}/events?organizationId=${organization._id}`
);
data = (await response.json()).data ?? [];
} else {
const response = await fetch(`${apiUrl()}/events`, {
cache: 'no-store',
});
const response = await fetch(`${apiUrl()}/events`);
data = (await response.json()).data ?? [];
}

Expand Down Expand Up @@ -69,9 +66,7 @@ export async function fetchEvent({
return null;
}

const data = await fetch(`${apiUrl()}/events/${eventId ?? eventSlug}`, {
cache: 'no-store',
});
const data = await fetch(`${apiUrl()}/events/${eventId ?? eventSlug}`);

if (!data.ok) {
return null;
Expand Down
11 changes: 2 additions & 9 deletions packages/app/lib/services/organizationService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ export async function fetchOrganization({
const response = await fetch(
`${apiUrl()}/organizations/${
organizationId ? organizationId : organizationSlug
}`,
{
cache: 'no-store',
}
}`
);
const data = (await response.json()).data;

Expand All @@ -33,9 +30,7 @@ export async function fetchOrganization({

export async function fetchOrganizations(): Promise<IExtendedOrganization[]> {
try {
const response = await fetch(`${apiUrl()}/organizations`, {
cache: 'no-store',
});
const response = await fetch(`${apiUrl()}/organizations`);
return (await response.json()).data ?? [];
} catch (e) {
console.log(e);
Expand Down Expand Up @@ -166,7 +161,6 @@ export async function fetchOrganizationMembers({
'Content-Type': 'application/json',
Authorization: `Bearer ${authToken}`,
},
cache: 'no-store',
}
);

Expand Down Expand Up @@ -231,7 +225,6 @@ export async function fetchOrganizationSocials({
'Content-Type': 'application/json',
Authorization: `Bearer ${authToken}`,
},
cache: 'no-store',
}
);
const data = (await response.json()).data;
Expand Down
112 changes: 111 additions & 1 deletion packages/app/lib/services/sessionService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,120 @@
import { ISessionModel } from 'streameth-new-server/src/interfaces/session.interface';
import { IExtendedSession } from '../types';
import { IExtendedSession, IPagination } from '../types';
import { apiUrl } from '@/lib/utils/utils';
import { Livepeer } from 'livepeer';
import { ISession } from 'streameth-new-server/src/interfaces/session.interface';
import { revalidatePath } from 'next/cache';
import { Asset } from 'livepeer/models/components';
import FuzzySearch from 'fuzzy-search';

interface ApiParams {
event?: string;
organization?: string;
stageId?: string;
page?: number;
size?: number;
onlyVideos?: boolean;
published?: boolean;
speakerIds?: string[]; // Assuming speakerIds is an array of strings
date?: Date;
type?: string;
}

function constructApiUrl(baseUrl: string, params: ApiParams): string {
const queryParams = Object.entries(params)
.filter(([_, value]) => value !== undefined && value !== null)
.map(([key, value]) => {
const formattedValue = Array.isArray(value) ? value.join(',') : value;
return `${encodeURIComponent(key)}=${encodeURIComponent(formattedValue)}`;
})
.join('&');
return `${baseUrl}?${queryParams}`;
}

export async function fetchAllSessions({
event,
organizationSlug,
stageId,
speakerIds,
onlyVideos,
published,
page = 1,
limit,
searchQuery = '',
type,
}: {
event?: string;
organizationSlug?: string;
stageId?: string;
speakerIds?: string[];
onlyVideos?: boolean;
published?: boolean;
page?: number;
limit?: number;
searchQuery?: string;
type?: string;
}): Promise<{
sessions: IExtendedSession[];
pagination: IPagination;
}> {
const params: ApiParams = {
event,
stageId,
organization: organizationSlug,
page,
size: searchQuery ? 0 : limit,
onlyVideos,
published,
speakerIds,
type,
};

const response = await fetch(
constructApiUrl(`${apiUrl()}/sessions`, params),
{
cache: 'no-store',
}
);
const a = await response.json();
const allSessions = a.data;
if (searchQuery) {
const normalizedQuery = searchQuery.toLowerCase();
const fuzzySearch = new FuzzySearch(
allSessions?.sessions,
['name', 'description', 'speakers.name'],
{
caseSensitive: false,
sort: true,
}
);

allSessions.sessions = fuzzySearch.search(normalizedQuery);
}

// Calculate total items and total pages
const totalItems = searchQuery
? allSessions.sessions.length
: allSessions.totalDocuments;
const totalPages = limit ? Math.ceil(totalItems / limit) : 1;

// Implement manual pagination for fuzzy search
const startIndex = (page - 1) * limit!;
const endIndex = startIndex + limit!;
const paginatedSessions = allSessions.sessions.slice(startIndex, endIndex);

// Return paginated data and pagination metadata
return {
sessions: searchQuery ? paginatedSessions : allSessions.sessions,
pagination: allSessions?.pagination
? allSessions.pagination
: {
currentPage: page,
totalPages,
totalItems,
limit,
},
};
}

export const createSession = async ({
session,
Expand Down

0 comments on commit 4bd30f7

Please sign in to comment.