From 168ed3215f659d44215fd02ac05cc1fe58be4e06 Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Mon, 20 Dec 2021 22:59:32 +0100
Subject: chore: create search view

---
 src/pages/recherche/index.tsx | 110 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 src/pages/recherche/index.tsx

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

diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
new file mode 100644
index 0000000..6de5816
--- /dev/null
+++ b/src/pages/recherche/index.tsx
@@ -0,0 +1,110 @@
+import { Button } from '@components/Buttons';
+import Layout from '@components/Layouts/Layout';
+import PostsList from '@components/PostsList/PostsList';
+import { config } from '@config/website';
+import { t } from '@lingui/macro';
+import { getPublishedPosts } from '@services/graphql/queries';
+import { NextPageWithLayout } from '@ts/types/app';
+import { PostsList as PostsListData } from '@ts/types/blog';
+import { loadTranslation } from '@utils/helpers/i18n';
+import { GetStaticProps } from 'next';
+import Head from 'next/head';
+import { useRouter } from 'next/router';
+import { ReactElement, useEffect, useState } from 'react';
+import useSWRInfinite from 'swr/infinite';
+
+const Search: NextPageWithLayout = () => {
+  const [query, setQuery] = useState('');
+  const router = useRouter();
+
+  useEffect(() => {
+    if (!router.isReady) return;
+
+    if (router.query?.s && typeof router.query.s === 'string') {
+      setQuery(router.query.s);
+    }
+  }, [router.isReady, router.query.s]);
+
+  const getKey = (pageIndex: number, previousData: PostsListData) => {
+    if (previousData && !previousData.posts) return null;
+
+    const args =
+      pageIndex === 0
+        ? { first: config.postsPerPage, searchQuery: query }
+        : {
+            first: config.postsPerPage,
+            after: previousData.pageInfo.endCursor,
+            searchQuery: query,
+          };
+
+    return args;
+  };
+
+  const { data, error, size, setSize } = useSWRInfinite(
+    getKey,
+    getPublishedPosts
+  );
+
+  const head = {
+    title: t`Search results for ${query}] | Armand Philippot`,
+    description: t`Discover search results for ${query}].`,
+  };
+
+  const isLoadingInitialData = !data && !error;
+  const isLoadingMore: boolean =
+    isLoadingInitialData ||
+    (size > 0 && data !== undefined && typeof data[size - 1] === 'undefined');
+
+  if (error) return <div>{t`Failed to load.`}</div>;
+  if (!data) return <div>{t`Loading...`}</div>;
+
+  const hasNextPage = data && data[data.length - 1].pageInfo.hasNextPage;
+
+  return (
+    <>
+      <Head>
+        <title>{head.title}</title>
+        <meta name="description" content={head.description} />
+      </Head>
+      <article>
+        <header>
+          <h1>
+            {query
+              ? t`Search results for: ${query}`
+              : t({
+                  id: 'msg.search',
+                  comment: 'Search page title',
+                  message: 'Search',
+                })}
+          </h1>
+        </header>
+        <div>
+          <PostsList data={data} showYears={false} />
+          {hasNextPage && (
+            <Button
+              isDisabled={isLoadingMore}
+              clickHandler={() => setSize(size + 1)}
+            >{t`Load more?`}</Button>
+          )}
+        </div>
+      </article>
+    </>
+  );
+};
+
+Search.getLayout = (page: ReactElement) => <Layout>{page}</Layout>;
+
+export const getStaticProps: GetStaticProps = async (context) => {
+  const translation = await loadTranslation(
+    context.locale!,
+    process.env.NODE_ENV === 'production'
+  );
+
+  return {
+    props: {
+      translation,
+    },
+  };
+};
+
+export default Search;
-- 
cgit v1.2.3

