aboutsummaryrefslogtreecommitdiffstats
path: root/src/pages/blog
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-05-13 15:39:55 +0200
committerArmand Philippot <git@armandphilippot.com>2022-05-13 15:46:05 +0200
commitdab72bb270ee2ee47a0b472d5e9e240cba7cbf0f (patch)
treea64a49a1048eeab1204a9b04923135edd1f259e1 /src/pages/blog
parentc5b516e2c933e77b2550fe6becebacb3fbdd30eb (diff)
chore: handle blog pagination
Diffstat (limited to 'src/pages/blog')
-rw-r--r--src/pages/blog/index.tsx110
1 files changed, 91 insertions, 19 deletions
diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx
index dc72388..1e7581c 100644
--- a/src/pages/blog/index.tsx
+++ b/src/pages/blog/index.tsx
@@ -1,11 +1,17 @@
-import ProgressBar from '@components/atoms/loaders/progress-bar';
-import { BreadcrumbItem } from '@components/molecules/nav/breadcrumb';
-import PostsList, { Post } from '@components/organisms/layout/posts-list';
+import { type BreadcrumbItem } from '@components/molecules/nav/breadcrumb';
+import PostsList, { type Post } from '@components/organisms/layout/posts-list';
import PageLayout from '@components/templates/page/page-layout';
-import { getArticles, getTotalArticles } from '@services/graphql/articles';
-import { Article, Meta } from '@ts/types/app';
+import { type EdgesResponse } from '@services/graphql/api';
+import {
+ getArticleFromRawData,
+ getArticles,
+ getTotalArticles,
+} from '@services/graphql/articles';
+import { type Article, type Meta } from '@ts/types/app';
+import { type RawArticle } from '@ts/types/raw-data';
import { settings } from '@utils/config';
-import { loadTranslation, Messages } from '@utils/helpers/i18n';
+import { loadTranslation, type Messages } from '@utils/helpers/i18n';
+import usePagination from '@utils/hooks/use-pagination';
import useSettings from '@utils/hooks/use-settings';
import { GetStaticProps, NextPage } from 'next';
import Head from 'next/head';
@@ -15,15 +21,15 @@ import { useIntl } from 'react-intl';
import { Blog, Graph, WebPage } from 'schema-dts';
type BlogPageProps = {
- posts: Article[];
- totalPosts: number;
+ articles: EdgesResponse<RawArticle>;
+ totalArticles: number;
translation: Messages;
};
/**
* Blog index page.
*/
-const BlogPage: NextPage<BlogPageProps> = ({ posts, totalPosts }) => {
+const BlogPage: NextPage<BlogPageProps> = ({ articles, totalArticles }) => {
const intl = useIntl();
const title = intl.formatMessage({
defaultMessage: 'Blog',
@@ -40,7 +46,7 @@ const BlogPage: NextPage<BlogPageProps> = ({ posts, totalPosts }) => {
{ id: 'blog', name: title, url: '/blog' },
];
- const { website } = useSettings();
+ const { blog, website } = useSettings();
const { asPath } = useRouter();
const pageTitle = intl.formatMessage(
{
@@ -98,11 +104,17 @@ const BlogPage: NextPage<BlogPageProps> = ({ posts, totalPosts }) => {
id: 'OF5cPz',
description: 'BlogPage: posts count meta',
},
- { postsCount: totalPosts }
+ { postsCount: totalArticles }
);
- const getPostMeta = (data: Meta<'article'>): Post['meta'] => {
- const { commentsCount, dates, thematics, wordsCount } = data;
+ /**
+ * Retrieve the formatted meta.
+ *
+ * @param {Meta<'article'>} meta - The article meta.
+ * @returns {Post['meta']} The formatted meta.
+ */
+ const getPostMeta = (meta: Meta<'article'>): Post['meta'] => {
+ const { commentsCount, dates, thematics, wordsCount } = meta;
return {
commentsCount,
@@ -114,7 +126,13 @@ const BlogPage: NextPage<BlogPageProps> = ({ posts, totalPosts }) => {
};
};
- const getPosts = (): Post[] => {
+ /**
+ * Retrieve the formatted posts.
+ *
+ * @param {Article[]} posts - An array of articles.
+ * @returns {Post[]} An array of formatted posts.
+ */
+ const getPosts = (posts: Article[]): Post[] => {
return posts.map((post) => {
return {
...post,
@@ -126,6 +144,45 @@ const BlogPage: NextPage<BlogPageProps> = ({ posts, totalPosts }) => {
});
};
+ /**
+ * Retrieve the posts list from raw data.
+ *
+ * @param {EdgesResponse<RawArticle>[]} rawData - The raw data.
+ * @returns {Post[]} An array of posts.
+ */
+ const getPostsList = (rawData: EdgesResponse<RawArticle>[]): Post[] => {
+ const articlesList: RawArticle[] = [];
+ rawData.forEach((articleData) =>
+ articleData.edges.forEach((edge) => {
+ articlesList.push(edge.node);
+ })
+ );
+
+ return getPosts(
+ articlesList.map((article) => getArticleFromRawData(article))
+ );
+ };
+
+ const {
+ data,
+ error,
+ isLoadingInitialData,
+ isLoadingMore,
+ hasNextPage,
+ setSize,
+ } = usePagination<RawArticle>({
+ fallbackData: [articles],
+ fetcher: getArticles,
+ perPage: blog.postsPerPage,
+ });
+
+ /**
+ * Load more posts handler.
+ */
+ const loadMore = () => {
+ setSize((prevSize) => prevSize + 1);
+ };
+
return (
<>
<Head>
@@ -146,21 +203,36 @@ const BlogPage: NextPage<BlogPageProps> = ({ posts, totalPosts }) => {
breadcrumb={breadcrumb}
headerMeta={{ total: postsCount }}
>
- <PostsList posts={getPosts()} byYear={true} total={totalPosts} />
+ {data && (
+ <PostsList
+ byYear={true}
+ isLoading={isLoadingMore || isLoadingInitialData}
+ loadMore={loadMore}
+ posts={getPostsList(data)}
+ showLoadMoreBtn={hasNextPage}
+ total={totalArticles}
+ />
+ )}
+ {error &&
+ intl.formatMessage({
+ defaultMessage: 'Failed to load.',
+ description: 'BlogPage: failed to load text',
+ id: 'C/XGkH',
+ })}
</PageLayout>
</>
);
};
export const getStaticProps: GetStaticProps = async ({ locale }) => {
- const posts = await getArticles({ first: settings.postsPerPage });
- const totalPosts = await getTotalArticles();
+ const articles = await getArticles({ first: settings.postsPerPage });
+ const totalArticles = await getTotalArticles();
const translation = await loadTranslation(locale);
return {
props: {
- posts: JSON.parse(JSON.stringify(posts.articles)),
- totalPosts,
+ articles: JSON.parse(JSON.stringify(articles)),
+ totalArticles,
translation,
},
};