diff --git a/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx b/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx
index cd6e200..3fd1d9f 100644
--- a/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx
+++ b/src/features/Projects/Components/ProjectCardMini/ProjectCardMini.tsx
@@ -12,7 +12,7 @@ export default function ProjectCardMini({ project, onClick }: Props) {
return (
{
e.key !== 'Enter' || onClick(project?.id!)
}}
diff --git a/src/features/Projects/pages/ExplorePage/ExplorePage.tsx b/src/features/Projects/pages/ExplorePage/ExplorePage.tsx
index d98d85f..c1d22aa 100644
--- a/src/features/Projects/pages/ExplorePage/ExplorePage.tsx
+++ b/src/features/Projects/pages/ExplorePage/ExplorePage.tsx
@@ -4,7 +4,7 @@ import { useExplorePageQuery } from 'src/graphql';
import ProjectsGrid from './ProjectsGrid/ProjectsGrid';
import { Helmet } from "react-helmet";
import Categories, { Category } from '../../Components/Categories/Categories';
-import { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useRef, useState } from 'react';
import Header from './Header/Header';
import Button from 'src/Components/Button/Button';
import { useAppDispatch } from 'src/utils/hooks';
@@ -13,10 +13,12 @@ import { createAction } from '@reduxjs/toolkit';
import { useReduxEffect } from 'src/utils/hooks/useReduxEffect';
import { NetworkStatus } from '@apollo/client';
import { FiSliders } from 'react-icons/fi';
+import { HiOutlineChevronDoubleDown } from 'react-icons/hi'
import { ProjectsFilters } from './Filters/FiltersModal';
const UPDATE_FILTERS_ACTION = createAction
>('PROJECTS_FILTERS_UPDATED')({})
+
type QueryFilter = Partial<{
categoryId: string[] | null
tags: string[] | null
@@ -25,11 +27,15 @@ type QueryFilter = Partial<{
license: string | null
}>
+const PAGE_SIZE = 20;
+
export default function ExplorePage() {
const dispatch = useAppDispatch();
const [filters, setFilters] = useState | null>(null)
const [selectedCategory, setSelectedCategory] = useState(null)
+ const projectsLength = useRef(0);
+ const [canFetchMore, setCanFetchMore] = useState(true);
const { queryFilters, hasSearchFilters } = useMemo(() => {
let filter: QueryFilter = {}
@@ -68,23 +74,30 @@ export default function ExplorePage() {
return { queryFilters: filter, hasSearchFilters };
}, [filters, selectedCategory?.id])
- const { data, networkStatus, error } = useExplorePageQuery({
+ const { data, networkStatus, error, fetchMore } = useExplorePageQuery({
variables: {
page: 1,
- pageSize: 20,
+ pageSize: PAGE_SIZE,
filter: queryFilters
},
notifyOnNetworkStatusChange: true,
+ onCompleted: data => {
+ if ((data.projects?.length ?? 0) < PAGE_SIZE) setCanFetchMore(false);
+ }
});
+ projectsLength.current = data?.projects?.length ?? 0;
+
const onFiltersUpdated = useCallback(({ payload }: typeof UPDATE_FILTERS_ACTION) => {
setSelectedCategory(null)
+ setCanFetchMore(true);
if (Object.keys(payload).length === 0)
setFilters(null);
else
setFilters(payload);
+
}, [])
useReduxEffect(onFiltersUpdated, UPDATE_FILTERS_ACTION.type)
@@ -110,6 +123,14 @@ export default function ExplorePage() {
const selectCategoryTab = (category: Category | null) => {
setSelectedCategory(category);
+ setCanFetchMore(true);
+ }
+
+ const clickFetchMore = () => {
+ fetchMore({ variables: { page: Math.floor((data?.projects?.length ?? 0) / PAGE_SIZE) + 1 } })
+ .then(res => {
+ if (!res.data.projects || res.data.projects.length < PAGE_SIZE) setCanFetchMore(false);
+ })
}
if (error) {
@@ -120,6 +141,8 @@ export default function ExplorePage() {
const isLoading = networkStatus === NetworkStatus.loading || networkStatus === NetworkStatus.refetch || networkStatus === NetworkStatus.setVariables;
+ const isLoadingMore = networkStatus === NetworkStatus.fetchMore;
+ const canLoadMore = !isLoading && !isLoadingMore && data?.projects && data.projects.length > 0 && canFetchMore;
return (
@@ -146,8 +169,12 @@ export default function ExplorePage() {
p !== null) as any[] ?? []}
/>
+ {canLoadMore &&
+
+
}
>
diff --git a/src/features/Projects/pages/ExplorePage/ProjectsGrid/ProjectsGrid.tsx b/src/features/Projects/pages/ExplorePage/ProjectsGrid/ProjectsGrid.tsx
index ba5c063..f8b54b3 100644
--- a/src/features/Projects/pages/ExplorePage/ProjectsGrid/ProjectsGrid.tsx
+++ b/src/features/Projects/pages/ExplorePage/ProjectsGrid/ProjectsGrid.tsx
@@ -7,10 +7,11 @@ import { ProjectCard } from 'src/utils/interfaces';
interface Props {
isLoading?: boolean;
+ isLoadingMore?: boolean;
projects: ProjectCard[]
}
-export default function ProjectsGrid({ isLoading, projects }: Props) {
+export default function ProjectsGrid({ isLoading, isLoadingMore, projects }: Props) {
const dispatch = useAppDispatch();
@@ -33,6 +34,8 @@ export default function ProjectsGrid({ isLoading, projects }: Props) {
{isLoading && Array(12).fill(0).map((_, idx) =>
)}
{!isLoading && projects.length === 0 &&
No results found here...
}
{!isLoading && projects.map((project) =>
)}
+
+ {isLoadingMore && Array(4).fill(0).map((_, idx) =>
)}
)
}
diff --git a/src/utils/apollo.ts b/src/utils/apollo.ts
index acaba74..647180f 100644
--- a/src/utils/apollo.ts
+++ b/src/utils/apollo.ts
@@ -54,7 +54,7 @@ export const apolloClient = new ApolloClient({
typePolicies: {
Query: {
fields: {
- getFeed: offsetLimitPagination(['sortBy', 'tag'])
+ projects: offsetLimitPagination(['_filter'])
},
},
},
@@ -72,10 +72,11 @@ function offsetLimitPagination