From abe043faaca0975ed92931d16d70a064c21a5c82 Mon Sep 17 00:00:00 2001 From: Maruf Bepary Date: Sun, 17 May 2026 20:43:24 +0100 Subject: [PATCH 1/2] refactor: replace infinite scroll intersection observers with manual load more buttons in post and community feeds --- .gitignore | 7 +++++-- app/communities/page.tsx | 30 ++++++++++-------------------- app/page.tsx | 20 ++++++++++---------- components/posts/Posts.tsx | 20 ++++++++++---------- hooks/posts/usePostsFeed.ts | 18 +++--------------- 5 files changed, 38 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index df674d3..a3ae63f 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,9 @@ next-env.d.ts .firebase/logs/vsce-debug.log AGENTS.md -# github +# ai .github/agents/** -.github/copilot-instructions.md \ No newline at end of file +.github/copilot-instructions.md +graphify-out +GEMINI.md +AGENTS.md \ No newline at end of file diff --git a/app/communities/page.tsx b/app/communities/page.tsx index 1d71a61..962aa49 100644 --- a/app/communities/page.tsx +++ b/app/communities/page.tsx @@ -7,9 +7,8 @@ import CommunityLoader from "@/components/loaders/CommunityLoader"; import useCommunitiesFeed from "@/hooks/community/useCommunitiesFeed"; import useCommunityState from "@/hooks/community/useCommunityState"; import useCommunityMembershipActions from "@/hooks/community/useCommunityMembershipActions"; -import { useIntersectionObserver } from "@/hooks/useIntersectionObserver"; -import { Box, Heading, Spinner, Stack, Text } from "@chakra-ui/react"; -import React, { useEffect, useMemo } from "react"; +import { Box, Button, Heading, Stack, Text } from "@chakra-ui/react"; +import React, { useMemo } from "react"; import { Community } from "@/types/community"; /** @@ -23,14 +22,6 @@ const Communities: React.FC = () => { const { onJoinOrLeaveCommunity } = useCommunityMembershipActions(); const { communities, loading, fetchCommunities, noMoreCommunities } = useCommunitiesFeed({ limitValue: 10, isPagination: true }); - const observerOptions = useMemo(() => ({ threshold: 0.5 }), []); - const { ref, isIntersecting } = useIntersectionObserver(observerOptions); - - useEffect(() => { - if (isIntersecting && !loading && !noMoreCommunities) { - fetchCommunities(false); - } - }, [isIntersecting, loading, noMoreCommunities, fetchCommunities]); const [adminCommunities, subscribedCommunities, notSubscribedCommunities] = useMemo(() => { @@ -127,16 +118,15 @@ const Communities: React.FC = () => { )} {!noMoreCommunities ? ( - fetchCommunities(false)} + loading={loading} + variant="outline" + width="100%" + my={4} > - {loading && } - + Load More + ) : ( No more communities diff --git a/app/page.tsx b/app/page.tsx index 32372c9..6389cd1 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -15,7 +15,7 @@ import usePostVote from "@/hooks/posts/usePostVote"; import usePostVoteSync from "@/hooks/posts/usePostVoteSync"; import usePostsFeed from "@/hooks/posts/usePostsFeed"; import useCustomToast from "@/hooks/useCustomToast"; -import { Box, Spinner, Stack, Text } from "@chakra-ui/react"; +import { Button, Stack, Text } from "@chakra-ui/react"; import { useEffect, useMemo } from "react"; import { useAuthState } from "react-firebase-hooks/auth"; @@ -43,7 +43,7 @@ export default function Home() { [communityStateValue.mySnippets] ); - const { loading, fetchPosts, ref, noMorePosts } = usePostsFeed({ + const { loading, fetchPosts, noMorePosts } = usePostsFeed({ communityIds: user && communityIds.length > 0 ? communityIds : undefined, isGenericHome: !user || communityIds.length === 0, }); @@ -116,15 +116,15 @@ export default function Home() { /> ))} {!noMorePosts ? ( - fetchPosts(false)} + loading={loading} + variant="outline" + width="100%" + my={4} > - {loading && } - + Load More + ) : ( No more posts diff --git a/components/posts/Posts.tsx b/components/posts/Posts.tsx index bba0b3c..c2f4e1a 100644 --- a/components/posts/Posts.tsx +++ b/components/posts/Posts.tsx @@ -8,7 +8,7 @@ import usePostVote from "@/hooks/posts/usePostVote"; import usePostDeletion from "@/hooks/posts/usePostDeletion"; import usePostVoteSync from "@/hooks/posts/usePostVoteSync"; import usePostsFeed from "@/hooks/posts/usePostsFeed"; -import { Box, Spinner, Stack, Text } from "@chakra-ui/react"; +import { Button, Stack, Text } from "@chakra-ui/react"; import React, { useEffect } from "react"; import { useAuthState } from "react-firebase-hooks/auth"; import PostLoader from "../loaders/post-loader/PostLoader"; @@ -33,7 +33,7 @@ const Posts: React.FC = ({ communityData }) => { usePostVoteSync(setPostStateValue); const { isAdmin, canPost } = useCommunityPermissions(communityData); - const { loading, fetchPosts, ref, noMorePosts } = usePostsFeed({ + const { loading, fetchPosts, noMorePosts } = usePostsFeed({ communityId: communityData.id, }); @@ -67,15 +67,15 @@ const Posts: React.FC = ({ communityData }) => { /> ))} {!noMorePosts ? ( - fetchPosts(false)} + loading={loading} + variant="outline" + width="100%" + my={4} > - {loading && } - + Load More + ) : ( No more posts diff --git a/hooks/posts/usePostsFeed.ts b/hooks/posts/usePostsFeed.ts index c8b1d2d..e7ecd6b 100644 --- a/hooks/posts/usePostsFeed.ts +++ b/hooks/posts/usePostsFeed.ts @@ -1,9 +1,8 @@ import { postStateAtom } from "@/atoms/postsAtom"; import { DocumentData, QueryDocumentSnapshot } from "firebase/firestore"; import { useSetAtom } from "jotai"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useState } from "react"; import useCustomToast from "../useCustomToast"; -import { useIntersectionObserver } from "../useIntersectionObserver"; import { Post } from "@/types/post"; import { getPosts as getPostsLib } from "@/lib/posts/getPosts"; @@ -15,11 +14,11 @@ type UsePostsFeedProps = { /** * A custom hook that manages the post feed for communities and the home page. - * It handles paginated fetching of posts and integrates with an intersection observer for infinite scrolling. + * It handles paginated fetching of posts. * @param communityId - Optional identifier to fetch posts for a specific community. * @param communityIds - Optional array of identifiers to fetch posts for a personalized home feed. * @param isGenericHome - Optional flag to fetch posts for the generic home feed. - * @returns An object containing the loading state, a ref for the intersection observer, and a flag for no more posts. + * @returns An object containing the loading state, fetchPosts function, and a flag for no more posts. */ const usePostsFeed = ({ communityId, @@ -33,9 +32,6 @@ const usePostsFeed = ({ const [noMorePosts, setNoMorePosts] = useState(false); const showToast = useCustomToast(); - const observerOptions = useMemo(() => ({ threshold: 0.5 }), []); - const { ref, isIntersecting } = useIntersectionObserver(observerOptions); - const fetchPosts = async (initial = false) => { if (loading) return; if (!initial && noMorePosts) return; @@ -74,13 +70,6 @@ const usePostsFeed = ({ } }; - useEffect(() => { - if (isIntersecting && !loading && !noMorePosts && lastVisible) { - fetchPosts(false); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isIntersecting, loading, noMorePosts, lastVisible]); - useEffect(() => { setNoMorePosts(false); setLastVisible(null); @@ -100,7 +89,6 @@ const usePostsFeed = ({ return { loading, fetchPosts, - ref, noMorePosts, }; }; From 11e20e847c0f9465745da9813e61c77f77aaa348 Mon Sep 17 00:00:00 2001 From: Maruf Bepary Date: Sun, 17 May 2026 20:52:25 +0100 Subject: [PATCH 2/2] fix: Docker CI task failing --- components/navbar/directory/MenuListItem.tsx | 1 + components/ui/CustomMenuButton.tsx | 1 + docker/next/Dockerfile | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/navbar/directory/MenuListItem.tsx b/components/navbar/directory/MenuListItem.tsx index be76c37..4e04b3a 100644 --- a/components/navbar/directory/MenuListItem.tsx +++ b/components/navbar/directory/MenuListItem.tsx @@ -39,6 +39,7 @@ const MenuListItem: React.FC = ({ return ( = ({ }) => { return (