From 56878f647ea0f1066fa3e222d7aa0d83057f496d Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Mon, 13 Nov 2023 17:45:59 +0100
Subject: refactor(components): rewrite PostsList component

* remove NoResults component and move logic to Search page
* add a usePostsList hook
* remove Pagination from PostsList (it is only used if javascript is
disabled and not on every posts list)
* replace `byYear` prop with `sortByYear`
* replace `loadMore` prop with `onLoadMore`
* remove `showLoadMoreBtn` (we can use `loadMore` prop instead to
determine if we need to display the button)
* replace `titleLevel` prop with `headingLvl`
* add `firstNewResult` prop to handle focus on the new results when
loading more article (we should not focus a useless span but the item
directly)
---
 src/pages/recherche/index.tsx | 69 +++++++++++++++++++++++++++++++++----------
 1 file changed, 54 insertions(+), 15 deletions(-)

(limited to 'src/pages/recherche/index.tsx')

diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
index a0e5057..effd087 100644
--- a/src/pages/recherche/index.tsx
+++ b/src/pages/recherche/index.tsx
@@ -3,6 +3,7 @@ import type { GetStaticProps } from 'next';
 import Head from 'next/head';
 import { useRouter } from 'next/router';
 import Script from 'next/script';
+import { useCallback } from 'react';
 import { useIntl } from 'react-intl';
 import {
   getLayout,
@@ -13,6 +14,8 @@ import {
   PageLayout,
   PostsList,
   Spinner,
+  SearchForm,
+  type SearchFormSubmit,
 } from '../../components';
 import {
   getArticles,
@@ -22,9 +25,9 @@ import {
   getTotalThematics,
   getTotalTopics,
 } from '../../services/graphql';
+import styles from '../../styles/pages/blog.module.scss';
 import type {
   NextPageWithLayout,
-  RawArticle,
   RawThematicPreview,
   RawTopicPreview,
 } from '../../types';
@@ -33,7 +36,6 @@ import {
   getBlogSchema,
   getLinksListItems,
   getPageLinkFromRawData,
-  getPostsList,
   getSchemaJson,
   getWebPageSchema,
 } from '../../utils/helpers';
@@ -41,7 +43,7 @@ import { loadTranslation, type Messages } from '../../utils/helpers/server';
 import {
   useBreadcrumb,
   useDataFromAPI,
-  usePagination,
+  usePostsList,
   useSettings,
 } from '../../utils/hooks';
 
@@ -59,7 +61,7 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
   topicsList,
 }) => {
   const intl = useIntl();
-  const { asPath, query } = useRouter();
+  const { asPath, query, push: routerPush } = useRouter();
   const title = query.s
     ? intl.formatMessage(
         {
@@ -116,14 +118,15 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
   const schemaJsonLd = getSchemaJson([webpageSchema, blogSchema]);
 
   const {
-    data,
     error,
+    firstNewResultIndex,
     isLoading,
     isLoadingMore,
     isRefreshing,
     hasNextPage,
     loadMore,
-  } = usePagination<RawArticle>({
+    posts,
+  } = usePostsList({
     fallback: [],
     fetcher: getArticles,
     perPage: blog.postsPerPage,
@@ -167,13 +170,33 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
     description: 'SearchPage: topics list widget title',
     id: 'N804XO',
   });
-  const postsListBaseUrl = `${ROUTES.SEARCH}/page/`;
   const loadingResults = intl.formatMessage({
     defaultMessage: 'Loading the search results...',
     description: 'SearchPage: loading search results message',
     id: 'EeCqAE',
   });
 
+  const searchSubmitHandler: SearchFormSubmit = useCallback(
+    ({ query: searchQuery }) => {
+      if (!searchQuery)
+        return {
+          messages: {
+            error: intl.formatMessage({
+              defaultMessage: 'Query must be longer than one character.',
+              description: 'NoResults: invalid query message',
+              id: 'VkfO7t',
+            }),
+          },
+          validator: (value) => value.query.length > 1,
+        };
+
+      routerPush({ pathname: ROUTES.SEARCH, query: { s: searchQuery } });
+
+      return undefined;
+    },
+    [intl, routerPush]
+  );
+
   return (
     <>
       <Head>
@@ -227,18 +250,34 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
           />,
         ]}
       >
-        {data && data.length > 0 ? (
+        {posts ? null : <Spinner>{loadingResults}</Spinner>}
+        {posts?.length ? (
           <PostsList
-            baseUrl={postsListBaseUrl}
-            byYear={true}
+            className={styles.list}
+            firstNewResult={firstNewResultIndex}
             isLoading={isLoading || isLoadingMore || isRefreshing}
-            loadMore={loadMore}
-            posts={getPostsList(data)}
-            showLoadMoreBtn={hasNextPage}
-            total={totalArticles ?? 0}
+            onLoadMore={hasNextPage ? loadMore : undefined}
+            posts={posts}
+            sortByYear
           />
         ) : (
-          <Spinner>{loadingResults}</Spinner>
+          <>
+            <p>
+              {intl.formatMessage({
+                defaultMessage: 'No results found.',
+                description: 'SearchPage: no results',
+                id: 'YV//MH',
+              })}
+            </p>
+            <p>
+              {intl.formatMessage({
+                defaultMessage: 'Would you like to try a new search?',
+                description: 'SearchPage: try a new search message',
+                id: 'vtDLzG',
+              })}
+            </p>
+            <SearchForm isLabelHidden onSubmit={searchSubmitHandler} />
+          </>
         )}
         {error ? (
           <Notice
-- 
cgit v1.2.3

