From 34e216546151eaf8a0a3cbb0bc8b65dae4c63bf2 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Mon, 23 May 2022 14:07:02 +0200
Subject: refactor: reduce the number of data transformation

---
 .../organisms/layout/posts-list.fixture.tsx        | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 src/components/organisms/layout/posts-list.fixture.tsx

(limited to 'src/components/organisms/layout/posts-list.fixture.tsx')

diff --git a/src/components/organisms/layout/posts-list.fixture.tsx b/src/components/organisms/layout/posts-list.fixture.tsx
new file mode 100644
index 0000000..b0afdf8
--- /dev/null
+++ b/src/components/organisms/layout/posts-list.fixture.tsx
@@ -0,0 +1,61 @@
+import { type Post } from './posts-list';
+
+export const introPost1 =
+  'Esse et voluptas sapiente modi impedit unde et. Ducimus nulla ea impedit sit placeat nihil assumenda. Rem est fugiat amet quo hic. Corrupti fuga quod animi autem dolorem ullam corrupti vel aut.';
+
+export const introPost2 =
+  'Illum quae asperiores quod aut necessitatibus itaque excepturi voluptas. Incidunt exercitationem ullam saepe alias consequatur sed. Quam veniam quaerat voluptatum earum quia quisquam fugiat sed perspiciatis. Et velit saepe est recusandae facilis eos eum ipsum.';
+
+export const introPost3 =
+  'Sunt aperiam ut rem impedit dolor id sit. Reprehenderit ipsum iusto fugiat. Quaerat laboriosam magnam facilis. Totam sint aliquam voluptatem in quis laborum sunt eum. Enim aut debitis officiis porro iure quia nihil voluptas ipsum. Praesentium quis necessitatibus cumque quia qui velit quos dolorem.';
+
+export const cover = {
+  alt: 'cover',
+  height: 480,
+  src: 'http://placeimg.com/640/480',
+  width: 640,
+};
+
+export const posts: Post[] = [
+  {
+    intro: introPost1,
+    id: 'post-1',
+    meta: {
+      cover,
+      dates: { publication: '2022-02-26' },
+      wordsCount: introPost1.split(' ').length,
+      thematics: [
+        { id: 1, name: 'Cat 1', slug: '#' },
+        { id: 2, name: 'Cat 2', slug: '#' },
+      ],
+      commentsCount: 1,
+    },
+    title: 'Ratione velit fuga',
+    url: '#',
+  },
+  {
+    intro: introPost2,
+    id: 'post-2',
+    meta: {
+      dates: { publication: '2022-02-20' },
+      wordsCount: introPost2.split(' ').length,
+      thematics: [{ id: 2, name: 'Cat 2', slug: '#' }],
+      commentsCount: 0,
+    },
+    title: 'Debitis laudantium laudantium',
+    url: '#',
+  },
+  {
+    intro: introPost3,
+    id: 'post-3',
+    meta: {
+      cover,
+      dates: { publication: '2021-12-20' },
+      wordsCount: introPost3.split(' ').length,
+      thematics: [{ id: 1, name: 'Cat 1', slug: '#' }],
+      commentsCount: 3,
+    },
+    title: 'Quaerat ut corporis',
+    url: '#',
+  },
+];
-- 
cgit v1.2.3


From c51b5d9a5f217f8aa59c4bdcb04eb3c87f5129b3 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Mon, 23 May 2022 19:32:42 +0200
Subject: fix: ensure all topics/thematics have the base url

---
 src/components/organisms/layout/posts-list.fixture.tsx |  8 ++++----
 src/components/organisms/layout/summary.fixture.tsx    |  4 ++--
 src/components/organisms/layout/summary.tsx            |  4 ++--
 src/pages/404.tsx                                      |  8 ++++----
 src/pages/article/[slug].tsx                           |  8 ++------
 src/pages/blog/index.tsx                               |  8 ++++----
 src/pages/blog/page/[number].tsx                       |  8 ++++----
 src/pages/recherche/index.tsx                          |  8 ++++----
 src/pages/sujet/[slug].tsx                             |  8 ++++----
 src/pages/thematique/[slug].tsx                        |  9 +++++----
 src/services/graphql/articles.ts                       |  4 ++--
 src/services/graphql/thematics.ts                      |  2 +-
 src/services/graphql/topics.ts                         |  2 +-
 src/ts/types/app.ts                                    |  2 +-
 src/utils/helpers/pages.ts                             | 16 ++++++----------
 15 files changed, 46 insertions(+), 53 deletions(-)

(limited to 'src/components/organisms/layout/posts-list.fixture.tsx')

diff --git a/src/components/organisms/layout/posts-list.fixture.tsx b/src/components/organisms/layout/posts-list.fixture.tsx
index b0afdf8..e3f2378 100644
--- a/src/components/organisms/layout/posts-list.fixture.tsx
+++ b/src/components/organisms/layout/posts-list.fixture.tsx
@@ -25,8 +25,8 @@ export const posts: Post[] = [
       dates: { publication: '2022-02-26' },
       wordsCount: introPost1.split(' ').length,
       thematics: [
-        { id: 1, name: 'Cat 1', slug: '#' },
-        { id: 2, name: 'Cat 2', slug: '#' },
+        { id: 1, name: 'Cat 1', url: '#' },
+        { id: 2, name: 'Cat 2', url: '#' },
       ],
       commentsCount: 1,
     },
@@ -39,7 +39,7 @@ export const posts: Post[] = [
     meta: {
       dates: { publication: '2022-02-20' },
       wordsCount: introPost2.split(' ').length,
-      thematics: [{ id: 2, name: 'Cat 2', slug: '#' }],
+      thematics: [{ id: 2, name: 'Cat 2', url: '#' }],
       commentsCount: 0,
     },
     title: 'Debitis laudantium laudantium',
@@ -52,7 +52,7 @@ export const posts: Post[] = [
       cover,
       dates: { publication: '2021-12-20' },
       wordsCount: introPost3.split(' ').length,
-      thematics: [{ id: 1, name: 'Cat 1', slug: '#' }],
+      thematics: [{ id: 1, name: 'Cat 1', url: '#' }],
       commentsCount: 3,
     },
     title: 'Quaerat ut corporis',
diff --git a/src/components/organisms/layout/summary.fixture.tsx b/src/components/organisms/layout/summary.fixture.tsx
index fbc46a5..bb3ebcb 100644
--- a/src/components/organisms/layout/summary.fixture.tsx
+++ b/src/components/organisms/layout/summary.fixture.tsx
@@ -14,8 +14,8 @@ export const meta: SummaryMeta = {
   dates: { publication: '2022-04-11' },
   wordsCount: intro.split(' ').length,
   thematics: [
-    { id: 1, name: 'Cat 1', slug: '#' },
-    { id: 2, name: 'Cat 2', slug: '#' },
+    { id: 1, name: 'Cat 1', url: '#' },
+    { id: 2, name: 'Cat 2', url: '#' },
   ],
   commentsCount: 1,
 };
diff --git a/src/components/organisms/layout/summary.tsx b/src/components/organisms/layout/summary.tsx
index ca51cd6..8807878 100644
--- a/src/components/organisms/layout/summary.tsx
+++ b/src/components/organisms/layout/summary.tsx
@@ -83,12 +83,12 @@ const Summary: FC<SummaryProps> = ({
           : undefined,
       readingTime,
       thematics: thematics?.map((thematic) => (
-        <Link key={thematic.id} href={thematic.slug}>
+        <Link key={thematic.id} href={thematic.url}>
           {thematic.name}
         </Link>
       )),
       topics: topics?.map((topic) => (
-        <Link key={topic.id} href={topic.slug}>
+        <Link key={topic.id} href={topic.url}>
           {topic.name}
         </Link>
       )),
diff --git a/src/pages/404.tsx b/src/pages/404.tsx
index 4ab7784..fd7187a 100644
--- a/src/pages/404.tsx
+++ b/src/pages/404.tsx
@@ -98,8 +98,9 @@ const Error404Page: NextPageWithLayout<Error404PageProps> = ({
           <LinksListWidget
             key="thematics-list"
             items={getLinksListItems(
-              thematicsList.map(getPageLinkFromRawData),
-              'thematic'
+              thematicsList.map((thematic) =>
+                getPageLinkFromRawData(thematic, 'thematic')
+              )
             )}
             title={thematicsListTitle}
             level={2}
@@ -107,8 +108,7 @@ const Error404Page: NextPageWithLayout<Error404PageProps> = ({
           <LinksListWidget
             key="topics-list"
             items={getLinksListItems(
-              topicsList.map(getPageLinkFromRawData),
-              'topic'
+              topicsList.map((topic) => getPageLinkFromRawData(topic, 'topic'))
             )}
             title={topicsListTitle}
             level={2}
diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx
index c72d48e..5e75ae7 100644
--- a/src/pages/article/[slug].tsx
+++ b/src/pages/article/[slug].tsx
@@ -81,7 +81,7 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({
     thematics:
       thematics &&
       thematics.map((thematic) => (
-        <Link key={thematic.id} href={`/thematique/${thematic.slug}`}>
+        <Link key={thematic.id} href={thematic.url}>
           {thematic.name}
         </Link>
       )),
@@ -99,11 +99,7 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({
       label: footerMetaLabel,
       value: topics.map((topic) => {
         return (
-          <ButtonLink
-            key={topic.id}
-            target={`/sujet/${topic.slug}`}
-            className={styles.btn}
-          >
+          <ButtonLink key={topic.id} target={topic.url} className={styles.btn}>
             {topic.logo && <ResponsiveImage {...topic.logo} />} {topic.name}
           </ButtonLink>
         );
diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx
index cfd6f8c..3956308 100644
--- a/src/pages/blog/index.tsx
+++ b/src/pages/blog/index.tsx
@@ -153,8 +153,9 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
           <LinksListWidget
             key="thematics-list"
             items={getLinksListItems(
-              thematicsList.map(getPageLinkFromRawData),
-              'thematic'
+              thematicsList.map((thematic) =>
+                getPageLinkFromRawData(thematic, 'thematic')
+              )
             )}
             title={thematicsListTitle}
             level={2}
@@ -162,8 +163,7 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
           <LinksListWidget
             key="topics-list"
             items={getLinksListItems(
-              topicsList.map(getPageLinkFromRawData),
-              'topic'
+              topicsList.map((topic) => getPageLinkFromRawData(topic, 'topic'))
             )}
             title={topicsListTitle}
             level={2}
diff --git a/src/pages/blog/page/[number].tsx b/src/pages/blog/page/[number].tsx
index 78b1db4..b5efd27 100644
--- a/src/pages/blog/page/[number].tsx
+++ b/src/pages/blog/page/[number].tsx
@@ -148,8 +148,9 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
           <LinksListWidget
             key="thematics-list"
             items={getLinksListItems(
-              thematicsList.map(getPageLinkFromRawData),
-              'thematic'
+              thematicsList.map((thematic) =>
+                getPageLinkFromRawData(thematic, 'thematic')
+              )
             )}
             title={thematicsListTitle}
             level={2}
@@ -157,8 +158,7 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
           <LinksListWidget
             key="topics-list"
             items={getLinksListItems(
-              topicsList.map(getPageLinkFromRawData),
-              'topic'
+              topicsList.map((topic) => getPageLinkFromRawData(topic, 'topic'))
             )}
             title={topicsListTitle}
             level={2}
diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
index ab619fb..ffdbf44 100644
--- a/src/pages/recherche/index.tsx
+++ b/src/pages/recherche/index.tsx
@@ -165,8 +165,9 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
           <LinksListWidget
             key="thematics-list"
             items={getLinksListItems(
-              thematicsList.map(getPageLinkFromRawData),
-              'thematic'
+              thematicsList.map((thematic) =>
+                getPageLinkFromRawData(thematic, 'thematic')
+              )
             )}
             title={thematicsListTitle}
             level={2}
@@ -174,8 +175,7 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
           <LinksListWidget
             key="topics-list"
             items={getLinksListItems(
-              topicsList.map(getPageLinkFromRawData),
-              'topic'
+              topicsList.map((topic) => getPageLinkFromRawData(topic, 'topic'))
             )}
             title={topicsListTitle}
             level={2}
diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx
index 838f009..5c86720 100644
--- a/src/pages/sujet/[slug].tsx
+++ b/src/pages/sujet/[slug].tsx
@@ -138,13 +138,13 @@ const TopicPage: NextPageWithLayout<TopicPageProps> = ({
             ? [
                 <LinksListWidget
                   key="related-thematics"
-                  items={getLinksListItems(thematics, 'thematic')}
+                  items={getLinksListItems(thematics)}
                   title={thematicsListTitle}
                   level={2}
                 />,
                 <LinksListWidget
                   key="topics"
-                  items={getLinksListItems(topics, 'topic')}
+                  items={getLinksListItems(topics)}
                   title={topicsListTitle}
                   level={2}
                 />,
@@ -198,10 +198,10 @@ export const getStaticProps: GetStaticProps<TopicPageProps> = async ({
     first: totalTopics,
   });
   const allTopics = allTopicsEdges.edges.map((edge) =>
-    getPageLinkFromRawData(edge.node)
+    getPageLinkFromRawData(edge.node, 'topic')
   );
   const topicsLinks = allTopics.filter(
-    (topic) => topic.slug !== (params!.slug as TopicParams['slug'])
+    (topic) => topic.url !== `/sujet/${params!.slug as TopicParams['slug']}`
   );
   const translation = await loadTranslation(locale);
 
diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx
index 84ab134..0519731 100644
--- a/src/pages/thematique/[slug].tsx
+++ b/src/pages/thematique/[slug].tsx
@@ -118,13 +118,13 @@ const ThematicPage: NextPageWithLayout<ThematicPageProps> = ({
             ? [
                 <LinksListWidget
                   key="thematics"
-                  items={getLinksListItems(thematics, 'thematic')}
+                  items={getLinksListItems(thematics)}
                   title={thematicsListTitle}
                   level={2}
                 />,
                 <LinksListWidget
                   key="related-topics"
-                  items={getLinksListItems(topics, 'topic')}
+                  items={getLinksListItems(topics)}
                   title={topicsListTitle}
                   level={2}
                 />,
@@ -178,10 +178,11 @@ export const getStaticProps: GetStaticProps<ThematicPageProps> = async ({
     first: totalThematics,
   });
   const allThematics = allThematicsEdges.edges.map((edge) =>
-    getPageLinkFromRawData(edge.node)
+    getPageLinkFromRawData(edge.node, 'thematic')
   );
   const allThematicsLinks = allThematics.filter(
-    (thematic) => thematic.slug !== (params!.slug as ThematicParams['slug'])
+    (thematic) =>
+      thematic.url !== `/thematique/${params!.slug as ThematicParams['slug']}`
   );
   const translation = await loadTranslation(locale);
 
diff --git a/src/services/graphql/articles.ts b/src/services/graphql/articles.ts
index f0ba4e4..27406ac 100644
--- a/src/services/graphql/articles.ts
+++ b/src/services/graphql/articles.ts
@@ -82,10 +82,10 @@ export const getArticleFromRawData = (data: RawArticle): Article => {
         title: seo?.title || '',
       },
       thematics: acfPosts.postsInThematic?.map((thematic) =>
-        getPageLinkFromRawData(thematic)
+        getPageLinkFromRawData(thematic, 'thematic')
       ),
       topics: acfPosts.postsInTopic?.map((topic) =>
-        getPageLinkFromRawData(topic)
+        getPageLinkFromRawData(topic, 'topic')
       ),
       wordsCount: info.wordsCount,
     },
diff --git a/src/services/graphql/thematics.ts b/src/services/graphql/thematics.ts
index fd9d9f5..4dc69e7 100644
--- a/src/services/graphql/thematics.ts
+++ b/src/services/graphql/thematics.ts
@@ -79,7 +79,7 @@ export const getThematicFromRawData = (data: RawThematic): Thematic => {
     posts.forEach((post) => {
       if (post.acfPosts.postsInTopic) {
         post.acfPosts.postsInTopic.forEach((topic) =>
-          topics.push(getPageLinkFromRawData(topic))
+          topics.push(getPageLinkFromRawData(topic, 'topic'))
         );
       }
     });
diff --git a/src/services/graphql/topics.ts b/src/services/graphql/topics.ts
index 277580f..0b1971b 100644
--- a/src/services/graphql/topics.ts
+++ b/src/services/graphql/topics.ts
@@ -80,7 +80,7 @@ export const getTopicFromRawData = (data: RawTopic): Topic => {
     posts.forEach((post) => {
       if (post.acfPosts.postsInThematic) {
         post.acfPosts.postsInThematic.forEach((thematic) =>
-          thematics.push(getPageLinkFromRawData(thematic))
+          thematics.push(getPageLinkFromRawData(thematic, 'thematic'))
         );
       }
     });
diff --git a/src/ts/types/app.ts b/src/ts/types/app.ts
index cb5429b..7bf1541 100644
--- a/src/ts/types/app.ts
+++ b/src/ts/types/app.ts
@@ -103,7 +103,7 @@ export type PageLink = {
   id: number;
   logo?: Image;
   name: string;
-  slug: string;
+  url: string;
 };
 
 export type Article = Page<'article'>;
diff --git a/src/utils/helpers/pages.ts b/src/utils/helpers/pages.ts
index 1a388e1..773d454 100644
--- a/src/utils/helpers/pages.ts
+++ b/src/utils/helpers/pages.ts
@@ -21,15 +21,17 @@ import { getImageFromRawData } from './images';
  * @returns {PageLink} The link data (id, slug and title).
  */
 export const getPageLinkFromRawData = (
-  data: RawThematicPreview | RawTopicPreview
+  data: RawThematicPreview | RawTopicPreview,
+  kind: 'thematic' | 'topic'
 ): PageLink => {
   const { databaseId, featuredImage, slug, title } = data;
+  const baseUrl = kind === 'thematic' ? '/thematique/' : '/sujet/';
 
   return {
     id: databaseId,
     logo: featuredImage ? getImageFromRawData(featuredImage?.node) : undefined,
     name: title,
-    slug,
+    url: `${baseUrl}${slug}`,
   };
 };
 
@@ -37,19 +39,13 @@ export const getPageLinkFromRawData = (
  * Convert page link data to an array of links items.
  *
  * @param {PageLink[]} links - An array of page links.
- * @param {'thematic'|'topic'} kind - The page links kind.
  * @returns {LinksListItem[]} An array of links items.
  */
-export const getLinksListItems = (
-  links: PageLink[],
-  kind: 'thematic' | 'topic'
-): LinksListItems[] => {
-  const baseUrl = kind === 'thematic' ? '/thematique/' : '/sujet/';
-
+export const getLinksListItems = (links: PageLink[]): LinksListItems[] => {
   return links.map((link) => {
     return {
       name: link.name,
-      url: `${baseUrl}${link.slug}`,
+      url: link.url,
     };
   });
 };
-- 
cgit v1.2.3


From 1e982fb02a9967e0efdc76c93a44798a9f2dcb43 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Tue, 24 May 2022 16:44:29 +0200
Subject: chore: add a search form when posts list prints no results

---
 .../organisms/layout/no-results.stories.tsx        | 28 ++++++++
 .../organisms/layout/no-results.test.tsx           | 14 ++++
 src/components/organisms/layout/no-results.tsx     | 38 ++++++++++
 .../organisms/layout/posts-list.fixture.tsx        |  2 +
 .../organisms/layout/posts-list.stories.tsx        |  5 +-
 .../organisms/layout/posts-list.test.tsx           | 29 ++++++--
 src/components/organisms/layout/posts-list.tsx     | 81 ++++++++++------------
 .../templates/page/page-layout.stories.tsx         |  7 +-
 src/pages/blog/index.tsx                           |  1 +
 src/pages/blog/page/[number].tsx                   |  1 +
 src/pages/recherche/index.tsx                      |  1 +
 src/pages/sujet/[slug].tsx                         |  5 +-
 src/pages/thematique/[slug].tsx                    |  5 +-
 13 files changed, 164 insertions(+), 53 deletions(-)
 create mode 100644 src/components/organisms/layout/no-results.stories.tsx
 create mode 100644 src/components/organisms/layout/no-results.test.tsx
 create mode 100644 src/components/organisms/layout/no-results.tsx

(limited to 'src/components/organisms/layout/posts-list.fixture.tsx')

diff --git a/src/components/organisms/layout/no-results.stories.tsx b/src/components/organisms/layout/no-results.stories.tsx
new file mode 100644
index 0000000..aa2e51e
--- /dev/null
+++ b/src/components/organisms/layout/no-results.stories.tsx
@@ -0,0 +1,28 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react';
+import NoResultsComponent from './no-results';
+
+export default {
+  title: 'Organisms/Layout',
+  component: NoResultsComponent,
+  argTypes: {
+    searchPage: {
+      control: {
+        type: 'text',
+      },
+      description: 'The search results page.',
+      type: {
+        name: 'string',
+        required: true,
+      },
+    },
+  },
+} as ComponentMeta<typeof NoResultsComponent>;
+
+const Template: ComponentStory<typeof NoResultsComponent> = (args) => (
+  <NoResultsComponent {...args} />
+);
+
+export const NoResults = Template.bind({});
+NoResults.args = {
+  searchPage: '#',
+};
diff --git a/src/components/organisms/layout/no-results.test.tsx b/src/components/organisms/layout/no-results.test.tsx
new file mode 100644
index 0000000..7f57177
--- /dev/null
+++ b/src/components/organisms/layout/no-results.test.tsx
@@ -0,0 +1,14 @@
+import { render, screen } from '@test-utils';
+import NoResults from './no-results';
+
+describe('NoResults', () => {
+  it('renders a no results text', () => {
+    render(<NoResults searchPage="#" />);
+    expect(screen.getByText(/No results/gi)).toBeInTheDocument();
+  });
+
+  it('renders a search form', () => {
+    render(<NoResults searchPage="#" />);
+    expect(screen.getByRole('searchbox')).toBeInTheDocument();
+  });
+});
diff --git a/src/components/organisms/layout/no-results.tsx b/src/components/organisms/layout/no-results.tsx
new file mode 100644
index 0000000..2245dbf
--- /dev/null
+++ b/src/components/organisms/layout/no-results.tsx
@@ -0,0 +1,38 @@
+import SearchForm, {
+  type SearchFormProps,
+} from '@components/organisms/forms/search-form';
+import { FC } from 'react';
+import { useIntl } from 'react-intl';
+
+export type NoResultsProps = Pick<SearchFormProps, 'searchPage'>;
+
+/**
+ * NoResults component
+ *
+ * Renders a no results text with a search form.
+ */
+const NoResults: FC<NoResultsProps> = ({ searchPage }) => {
+  const intl = useIntl();
+
+  return (
+    <>
+      <p>
+        {intl.formatMessage({
+          defaultMessage: 'No results found.',
+          description: 'NoResults: no results',
+          id: '5O2vpy',
+        })}
+      </p>
+      <p>
+        {intl.formatMessage({
+          defaultMessage: 'Would you like to try a new search?',
+          description: 'NoResults: try a new search message',
+          id: 'DVBwfu',
+        })}
+      </p>
+      <SearchForm hideLabel={true} searchPage={searchPage} />
+    </>
+  );
+};
+
+export default NoResults;
diff --git a/src/components/organisms/layout/posts-list.fixture.tsx b/src/components/organisms/layout/posts-list.fixture.tsx
index e3f2378..97a746f 100644
--- a/src/components/organisms/layout/posts-list.fixture.tsx
+++ b/src/components/organisms/layout/posts-list.fixture.tsx
@@ -59,3 +59,5 @@ export const posts: Post[] = [
     url: '#',
   },
 ];
+
+export const searchPage = '#';
diff --git a/src/components/organisms/layout/posts-list.stories.tsx b/src/components/organisms/layout/posts-list.stories.tsx
index 68e3dc0..bff1f28 100644
--- a/src/components/organisms/layout/posts-list.stories.tsx
+++ b/src/components/organisms/layout/posts-list.stories.tsx
@@ -1,6 +1,6 @@
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import PostsList from './posts-list';
-import { posts } from './posts-list.fixture';
+import { posts, searchPage } from './posts-list.fixture';
 
 /**
  * PostsList - Storybook Meta
@@ -161,6 +161,7 @@ const Template: ComponentStory<typeof PostsList> = (args) => (
 export const Default = Template.bind({});
 Default.args = {
   posts,
+  searchPage,
   total: posts.length,
 };
 
@@ -171,6 +172,7 @@ export const ByYears = Template.bind({});
 ByYears.args = {
   posts,
   byYear: true,
+  searchPage,
   total: posts.length,
 };
 ByYears.decorators = [
@@ -187,5 +189,6 @@ ByYears.decorators = [
 export const NoResults = Template.bind({});
 NoResults.args = {
   posts: [],
+  searchPage,
   total: posts.length,
 };
diff --git a/src/components/organisms/layout/posts-list.test.tsx b/src/components/organisms/layout/posts-list.test.tsx
index 1bab466..e58a974 100644
--- a/src/components/organisms/layout/posts-list.test.tsx
+++ b/src/components/organisms/layout/posts-list.test.tsx
@@ -1,25 +1,46 @@
 import { render, screen } from '@test-utils';
 import PostsList from './posts-list';
-import { posts } from './posts-list.fixture';
+import { posts, searchPage } from './posts-list.fixture';
 
 describe('PostsList', () => {
   it('renders the correct number of posts', () => {
-    render(<PostsList posts={posts} total={posts.length} />);
+    render(
+      <PostsList posts={posts} total={posts.length} searchPage={searchPage} />
+    );
     expect(screen.getAllByRole('article')).toHaveLength(posts.length);
   });
 
   it('renders the number of loaded posts', () => {
-    render(<PostsList posts={posts} total={posts.length} />);
+    render(
+      <PostsList posts={posts} total={posts.length} searchPage={searchPage} />
+    );
     const info = `${posts.length} loaded articles out of a total of ${posts.length}`;
     expect(screen.getByText(info)).toBeInTheDocument();
   });
 
   it('renders a load more button', () => {
     render(
-      <PostsList posts={posts} total={posts.length} showLoadMoreBtn={true} />
+      <PostsList
+        posts={posts}
+        total={posts.length}
+        showLoadMoreBtn={true}
+        searchPage={searchPage}
+      />
     );
     expect(
       screen.getByRole('button', { name: /Load more/i })
     ).toBeInTheDocument();
   });
+
+  it('renders a search form if no results', () => {
+    render(
+      <PostsList
+        posts={[]}
+        total={0}
+        showLoadMoreBtn={true}
+        searchPage={searchPage}
+      />
+    );
+    expect(screen.getByRole('searchbox')).toBeInTheDocument();
+  });
 });
diff --git a/src/components/organisms/layout/posts-list.tsx b/src/components/organisms/layout/posts-list.tsx
index 91fc62d..24869fd 100644
--- a/src/components/organisms/layout/posts-list.tsx
+++ b/src/components/organisms/layout/posts-list.tsx
@@ -9,6 +9,7 @@ import useIsMounted from '@utils/hooks/use-is-mounted';
 import useSettings from '@utils/hooks/use-settings';
 import { FC, Fragment, useRef } from 'react';
 import { useIntl } from 'react-intl';
+import NoResults, { NoResultsProps } from './no-results';
 import styles from './posts-list.module.scss';
 import Summary, { type SummaryProps } from './summary';
 
@@ -23,40 +24,41 @@ export type YearCollection = {
   [key: string]: Post[];
 };
 
-export type PostsListProps = Pick<PaginationProps, 'baseUrl' | 'siblings'> & {
-  /**
-   * True to display the posts by year. Default: false.
-   */
-  byYear?: boolean;
-  /**
-   * Determine if the data is loading.
-   */
-  isLoading?: boolean;
-  /**
-   * Load more button handler.
-   */
-  loadMore?: () => void;
-  /**
-   * The current page number. Default: 1.
-   */
-  pageNumber?: number;
-  /**
-   * The posts data.
-   */
-  posts: Post[];
-  /**
-   * Determine if the load more button should be visible.
-   */
-  showLoadMoreBtn?: boolean;
-  /**
-   * The posts heading level (hn).
-   */
-  titleLevel?: HeadingLevel;
-  /**
-   * The total posts number.
-   */
-  total: number;
-};
+export type PostsListProps = Pick<PaginationProps, 'baseUrl' | 'siblings'> &
+  Pick<NoResultsProps, 'searchPage'> & {
+    /**
+     * True to display the posts by year. Default: false.
+     */
+    byYear?: boolean;
+    /**
+     * Determine if the data is loading.
+     */
+    isLoading?: boolean;
+    /**
+     * Load more button handler.
+     */
+    loadMore?: () => void;
+    /**
+     * The current page number. Default: 1.
+     */
+    pageNumber?: number;
+    /**
+     * The posts data.
+     */
+    posts: Post[];
+    /**
+     * Determine if the load more button should be visible.
+     */
+    showLoadMoreBtn?: boolean;
+    /**
+     * The posts heading level (hn).
+     */
+    titleLevel?: HeadingLevel;
+    /**
+     * The total posts number.
+     */
+    total: number;
+  };
 
 /**
  * Create a collection of posts sorted by year.
@@ -89,6 +91,7 @@ const PostsList: FC<PostsListProps> = ({
   loadMore,
   pageNumber = 1,
   posts,
+  searchPage,
   showLoadMoreBtn = false,
   siblings,
   titleLevel,
@@ -221,15 +224,7 @@ const PostsList: FC<PostsListProps> = ({
   };
 
   if (posts.length === 0) {
-    return (
-      <p>
-        {intl.formatMessage({
-          defaultMessage: 'No results found.',
-          description: 'PostsList: no results',
-          id: 'vK7Sxv',
-        })}
-      </p>
-    );
+    return <NoResults searchPage={searchPage} />;
   }
 
   return (
diff --git a/src/components/templates/page/page-layout.stories.tsx b/src/components/templates/page/page-layout.stories.tsx
index 88e3785..06c6c24 100644
--- a/src/components/templates/page/page-layout.stories.tsx
+++ b/src/components/templates/page/page-layout.stories.tsx
@@ -368,7 +368,12 @@ Blog.args = {
   headerMeta: { total: posts.length },
   children: (
     <>
-      <PostsList posts={posts} byYear={true} total={posts.length} />
+      <PostsList
+        posts={posts}
+        byYear={true}
+        total={posts.length}
+        searchPage="#"
+      />
     </>
   ),
   widgets: [
diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx
index 3956308..3f7eefd 100644
--- a/src/pages/blog/index.tsx
+++ b/src/pages/blog/index.tsx
@@ -177,6 +177,7 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
             isLoading={isLoadingMore || isLoadingInitialData}
             loadMore={loadMore}
             posts={getPostsList(data)}
+            searchPage="/recherche/"
             showLoadMoreBtn={hasNextPage}
             total={totalArticles}
           />
diff --git a/src/pages/blog/page/[number].tsx b/src/pages/blog/page/[number].tsx
index b5efd27..1e1240a 100644
--- a/src/pages/blog/page/[number].tsx
+++ b/src/pages/blog/page/[number].tsx
@@ -170,6 +170,7 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
           byYear={true}
           pageNumber={pageNumber}
           posts={getPostsList([articles])}
+          searchPage="/recherche/"
           total={totalArticles}
         />
       </PageLayout>
diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
index ffdbf44..dbbec55 100644
--- a/src/pages/recherche/index.tsx
+++ b/src/pages/recherche/index.tsx
@@ -189,6 +189,7 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
             isLoading={isLoadingMore || isLoadingInitialData}
             loadMore={loadMore}
             posts={getPostsList(data)}
+            searchPage="/recherche/"
             showLoadMoreBtn={hasNextPage}
             total={totalArticles || 0}
           />
diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx
index 5c86720..48924e5 100644
--- a/src/pages/sujet/[slug].tsx
+++ b/src/pages/sujet/[slug].tsx
@@ -167,10 +167,11 @@ const TopicPage: NextPageWithLayout<TopicPageProps> = ({
             </Heading>
             <PostsList
               baseUrl="/sujet/page/"
+              byYear={true}
               posts={getPostsWithUrl(articles)}
-              total={articles.length}
+              searchPage="/recherche/"
               titleLevel={3}
-              byYear={true}
+              total={articles.length}
             />
           </>
         )}
diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx
index 0519731..7aa6c1c 100644
--- a/src/pages/thematique/[slug].tsx
+++ b/src/pages/thematique/[slug].tsx
@@ -147,10 +147,11 @@ const ThematicPage: NextPageWithLayout<ThematicPageProps> = ({
             </Heading>
             <PostsList
               baseUrl="/thematique/page/"
+              byYear={true}
               posts={getPostsWithUrl(articles)}
-              total={articles.length}
+              searchPage="/recherche/"
               titleLevel={3}
-              byYear={true}
+              total={articles.length}
             />
           </>
         )}
-- 
cgit v1.2.3

