FIX: Fixed infinite scrolling for all categories page
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef, useState, useEffect } from "react";
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import ListRow from "../components/Layout/ListRow";
|
import ListRow from "../components/Layout/ListRow";
|
||||||
import DynamicPageContent from "../components/Layout/DynamicPageContent";
|
import DynamicPageContent from "../components/Layout/DynamicPageContent";
|
||||||
@@ -7,97 +7,93 @@ import LoadingScreen from "../components/Layout/LoadingScreen";
|
|||||||
import { CategoryType } from "../types/CategoryType";
|
import { CategoryType } from "../types/CategoryType";
|
||||||
|
|
||||||
const AllCategoriesPage: React.FC = () => {
|
const AllCategoriesPage: React.FC = () => {
|
||||||
|
const [categories, setCategories] = useState<CategoryType[]>([]);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [allCategories, setAllCategories] = useState<CategoryType[]>([]);
|
|
||||||
const [categoryOffset, setCategoryOffset] = useState(0);
|
const [categoryOffset, setCategoryOffset] = useState(0);
|
||||||
|
const [noCategories, setNoCategories] = useState(12);
|
||||||
const [hasMoreData, setHasMoreData] = useState(true);
|
const [hasMoreData, setHasMoreData] = useState(true);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const listRowRef = useRef<any>(null);
|
const listRowRef = useRef<any>(null);
|
||||||
|
const isLoading = useRef(false);
|
||||||
|
|
||||||
const fetchCategories = async () => {
|
const fetchCategories = async () => {
|
||||||
if (isLoading && categoryOffset > 0) return [];
|
// If already loading, skip this fetch
|
||||||
|
if (isLoading.current) return;
|
||||||
|
|
||||||
|
isLoading.current = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`Fetching categories with offset: ${categoryOffset}`);
|
const response = await fetch(`/api/categories/popular/${noCategories}/${categoryOffset}`);
|
||||||
const response = await fetch(
|
if (!response.ok) {
|
||||||
`/api/categories/popular/12/${categoryOffset}`
|
throw new Error("Failed to fetch categories");
|
||||||
);
|
}
|
||||||
if (!response.ok) throw new Error("Failed to fetch categories");
|
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log("Categories fetched:", data.length);
|
|
||||||
|
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
setHasMoreData(false);
|
setHasMoreData(false);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
setCategoryOffset(categoryOffset + data.length);
|
setCategoryOffset(prev => prev + data.length);
|
||||||
|
|
||||||
const newCategories = data.map((category: any) => ({
|
const processedCategories = data.map((category: any) => ({
|
||||||
type: "category" as const,
|
type: "category" as const,
|
||||||
id: category.category_id,
|
id: category.category_id,
|
||||||
title: category.category_name,
|
title: category.category_name,
|
||||||
viewers: category.num_viewers || 0,
|
viewers: category.num_viewers,
|
||||||
thumbnail: `/images/category_thumbnails/${category.category_name
|
thumbnail: `/images/category_thumbnails/${category.category_name
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/ /g, "_")}.webp`,
|
.replace(/ /g, "_")}.webp`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return newCategories;
|
setCategories(prev => [...prev, ...processedCategories]);
|
||||||
} catch (err) {
|
return processedCategories;
|
||||||
console.error("Error fetching categories:", err);
|
} catch (error) {
|
||||||
setHasMoreData(false);
|
console.error("Error fetching categories:", error);
|
||||||
return [];
|
return [];
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
isLoading.current = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initial load
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const initialLoad = async () => {
|
fetchCategories();
|
||||||
const initialCategories = await fetchCategories();
|
|
||||||
setAllCategories(initialCategories);
|
|
||||||
};
|
|
||||||
|
|
||||||
initialLoad();
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadMoreCategories = async () => {
|
const loadOnScroll = async () => {
|
||||||
if (!hasMoreData || (isLoading && categoryOffset > 0)) return;
|
if (hasMoreData && listRowRef.current) {
|
||||||
|
const newCategories = await fetchCategories();
|
||||||
const newCategories = await fetchCategories();
|
if (newCategories?.length > 0) {
|
||||||
if (newCategories.length > 0) {
|
|
||||||
setAllCategories(prev => [...prev, ...newCategories]);
|
|
||||||
if (listRowRef.current && listRowRef.current.addMoreItems) {
|
|
||||||
listRowRef.current.addMoreItems(newCategories);
|
listRowRef.current.addMoreItems(newCategories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set up infinite scroll
|
fetchContentOnScroll(loadOnScroll, hasMoreData);
|
||||||
fetchContentOnScroll(loadMoreCategories, hasMoreData);
|
|
||||||
|
if (hasMoreData && !categories.length) return <LoadingScreen />;
|
||||||
|
|
||||||
const handleCategoryClick = (categoryName: string) => {
|
const handleCategoryClick = (categoryName: string) => {
|
||||||
|
console.log(categoryName);
|
||||||
navigate(`/category/${categoryName}`);
|
navigate(`/category/${categoryName}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading && allCategories.length === 0) return <LoadingScreen />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DynamicPageContent className="min-h-screen">
|
<DynamicPageContent
|
||||||
|
className="min-h-screen bg-gradient-radial from-[#ff00f1] via-[#0400ff] to-[#ff0000]"
|
||||||
|
style={{ backgroundImage: "url(/images/background-pattern.svg)" }}
|
||||||
|
>
|
||||||
<ListRow
|
<ListRow
|
||||||
ref={listRowRef}
|
ref={listRowRef}
|
||||||
type="category"
|
type="category"
|
||||||
title="All Categories"
|
title="All Categories"
|
||||||
items={allCategories}
|
items={categories}
|
||||||
onItemClick={handleCategoryClick}
|
onClick={handleCategoryClick}
|
||||||
extraClasses="bg-[var(--recommend)] text-center"
|
extraClasses="bg-[var(--recommend)] text-center"
|
||||||
itemExtraClasses="w-[20vw]"
|
itemExtraClasses="w-[20vw]"
|
||||||
wrap={true}
|
wrap={true}
|
||||||
/>
|
/>
|
||||||
{!hasMoreData && allCategories.length > 0 && (
|
{!hasMoreData && !categories.length && (
|
||||||
<div className="text-center text-gray-500 p-4">
|
<div className="text-center text-gray-500 p-4">
|
||||||
No more categories to load
|
No more categories to load
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ const CategoryPage: React.FC = () => {
|
|||||||
|
|
||||||
setStreamOffset((prev) => prev + data.length);
|
setStreamOffset((prev) => prev + data.length);
|
||||||
|
|
||||||
const processedStreams: StreamType[] = data.map((stream: any) => ({
|
const processedStreams = data.map((stream: any) => ({
|
||||||
type: "stream",
|
type: "stream",
|
||||||
id: stream.user_id,
|
id: stream.user_id,
|
||||||
title: stream.title,
|
title: stream.title,
|
||||||
@@ -78,16 +78,16 @@ const CategoryPage: React.FC = () => {
|
|||||||
fetchCategoryStreams();
|
fetchCategoryStreams();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const logOnScroll = async () => {
|
const loadOnScroll = async () => {
|
||||||
if (hasMoreData && listRowRef.current) {
|
if (hasMoreData && listRowRef.current) {
|
||||||
const newCategories = await fetchCategoryStreams();
|
const newStreams = await fetchCategoryStreams();
|
||||||
if (newCategories && newCategories.length > 0) {
|
if (newStreams?.length > 0) {
|
||||||
listRowRef.current.addMoreItems(newCategories);
|
listRowRef.current.addMoreItems(newStreams);
|
||||||
} else console.log("No more data to fetch");
|
} else console.log("No more data to fetch");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchContentOnScroll(logOnScroll, hasMoreData);
|
fetchContentOnScroll(loadOnScroll, hasMoreData);
|
||||||
|
|
||||||
const handleStreamClick = (streamerName: string) => {
|
const handleStreamClick = (streamerName: string) => {
|
||||||
window.location.href = `/${streamerName}`;
|
window.location.href = `/${streamerName}`;
|
||||||
@@ -99,6 +99,7 @@ const CategoryPage: React.FC = () => {
|
|||||||
<DynamicPageContent className="min-h-screen bg-gradient-radial from-[#ff00f1] via-[#0400ff] to-[#ff0000]">
|
<DynamicPageContent className="min-h-screen bg-gradient-radial from-[#ff00f1] via-[#0400ff] to-[#ff0000]">
|
||||||
<div className="pt-8">
|
<div className="pt-8">
|
||||||
<ListRow
|
<ListRow
|
||||||
|
ref={listRowRef}
|
||||||
type="stream"
|
type="stream"
|
||||||
title={`${categoryName} Streams`}
|
title={`${categoryName} Streams`}
|
||||||
description={`Live streams in the ${categoryName} category`}
|
description={`Live streams in the ${categoryName} category`}
|
||||||
@@ -106,6 +107,7 @@ const CategoryPage: React.FC = () => {
|
|||||||
wrap={true}
|
wrap={true}
|
||||||
onItemClick={handleStreamClick}
|
onItemClick={handleStreamClick}
|
||||||
extraClasses="bg-[var(--recommend)]"
|
extraClasses="bg-[var(--recommend)]"
|
||||||
|
itemExtraClasses="w-[20vw]"
|
||||||
>
|
>
|
||||||
{isLoggedIn && (
|
{isLoggedIn && (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user