aboutsummaryrefslogtreecommitdiffstats
path: root/src/pages/recherche/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages/recherche/index.tsx')
-rw-r--r--src/pages/recherche/index.tsx365
1 files changed, 211 insertions, 154 deletions
diff --git a/src/pages/recherche/index.tsx b/src/pages/recherche/index.tsx
index 2bcb1c0..9eaecba 100644
--- a/src/pages/recherche/index.tsx
+++ b/src/pages/recherche/index.tsx
@@ -22,7 +22,6 @@ import {
import {
convertWPThematicPreviewToPageLink,
convertWPTopicPreviewToPageLink,
- fetchPostsCount,
fetchThematicsCount,
fetchThematicsList,
fetchTopicsCount,
@@ -30,6 +29,7 @@ import {
} from '../../services/graphql';
import styles from '../../styles/pages/blog.module.scss';
import type {
+ GraphQLConnection,
NextPageWithLayout,
WPThematicPreview,
WPTopicPreview,
@@ -47,78 +47,70 @@ import { loadTranslation, type Messages } from '../../utils/helpers/server';
import {
useArticlesList,
useBreadcrumb,
- useDataFromAPI,
+ useThematicsList,
+ useTopicsList,
} from '../../utils/hooks';
+const NoResults = () => {
+ const intl = useIntl();
+ const router = useRouter();
+
+ const searchSubmitHandler: SearchFormSubmit = useCallback(
+ async ({ query: searchQuery }) => {
+ if (!searchQuery)
+ return {
+ messages: {
+ error: intl.formatMessage({
+ defaultMessage: 'Query must be longer than one character.',
+ description: 'SearchPage: invalid query message',
+ id: 'e3ppRI',
+ }),
+ },
+ validator: (value) => value.query.length > 1,
+ };
+
+ await router.push({ pathname: ROUTES.SEARCH, query: { s: searchQuery } });
+
+ return undefined;
+ },
+ [intl, router]
+ );
+
+ return (
+ <div className={styles['no-results']}>
+ <p>
+ {router.query.s
+ ? intl.formatMessage({
+ defaultMessage:
+ 'No results found. Would you like to try a new search?',
+ description: 'SearchPage: no results',
+ id: 'E+ROR5',
+ })
+ : intl.formatMessage({
+ defaultMessage: 'Please use the form below to start searching:',
+ description: 'SearchPage: search for message',
+ id: 'A0TsHP',
+ })}
+ </p>
+ <SearchForm isLabelHidden onSubmit={searchSubmitHandler} />
+ </div>
+ );
+};
+
type SearchPageProps = {
- thematicsList: WPThematicPreview[];
- topicsList: WPTopicPreview[];
+ data: {
+ thematics: GraphQLConnection<WPThematicPreview>;
+ topics: GraphQLConnection<WPTopicPreview>;
+ };
translation: Messages;
};
/**
* Search page.
*/
-const SearchPage: NextPageWithLayout<SearchPageProps> = ({
- thematicsList,
- topicsList,
-}) => {
+const SearchPage: NextPageWithLayout<SearchPageProps> = ({ data }) => {
const intl = useIntl();
- const { asPath, query, push: routerPush } = useRouter();
- const title = query.s
- ? intl.formatMessage(
- {
- defaultMessage: 'Search results for {query}',
- description: 'SearchPage: SEO - Page title',
- id: 'ZNBhDP',
- },
- { query: query.s as string }
- )
- : intl.formatMessage({
- defaultMessage: 'Search',
- description: 'SearchPage: SEO - Page title',
- id: 'WDwNDl',
- });
- const { items: breadcrumbItems, schema: breadcrumbSchema } = useBreadcrumb({
- title,
- url: ROUTES.SEARCH,
- });
-
- const page = {
- title: `${title} - ${CONFIG.name}`,
- url: `${CONFIG.url}${asPath}`,
- };
- const pageDescription = query.s
- ? intl.formatMessage(
- {
- defaultMessage:
- 'Discover search results for {query} on {websiteName}.',
- description: 'SearchPage: SEO - Meta description',
- id: 'pg26sn',
- },
- { query: query.s as string, websiteName: CONFIG.name }
- )
- : intl.formatMessage(
- {
- defaultMessage: 'Search for a post on {websiteName}.',
- description: 'SearchPage: SEO - Meta description',
- id: 'npisb3',
- },
- { websiteName: CONFIG.name }
- );
- const webpageSchema = getWebPageSchema({
- description: pageDescription,
- locale: CONFIG.locales.defaultLocale,
- slug: asPath,
- title: page.title,
- });
- const blogSchema = getBlogSchema({
- isSinglePage: false,
- locale: CONFIG.locales.defaultLocale,
- slug: asPath,
- });
- const schemaJsonLd = getSchemaJson([webpageSchema, blogSchema]);
-
+ const { asPath, query } = useRouter();
const {
articles,
error,
@@ -129,68 +121,127 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
hasNextPage,
loadMore,
} = useArticlesList({
- fallback: [],
perPage: CONFIG.postsPerPage,
- searchQuery: query.s as string,
+ searchQuery: typeof query.s === 'string' ? query.s : undefined,
});
-
- const totalArticles = useDataFromAPI<number>(async () =>
- fetchPostsCount({ search: query.s as string })
- );
-
- const thematicsListTitle = intl.formatMessage({
- defaultMessage: 'Thematics',
- description: 'SearchPage: thematics list widget title',
- id: 'Dq6+WH',
- });
-
- const topicsListTitle = intl.formatMessage({
- defaultMessage: 'Topics',
- description: 'SearchPage: topics list widget title',
- id: 'N804XO',
+ const { isLoading: areThematicsLoading, thematics } = useThematicsList({
+ fallback: data.thematics,
+ input: { first: data.thematics.pageInfo.total },
});
- const loadingResults = intl.formatMessage({
- defaultMessage: 'Loading the search results...',
- description: 'SearchPage: loading search results message',
- id: 'EeCqAE',
+ const { isLoading: areTopicsLoading, topics } = useTopicsList({
+ fallback: data.topics,
+ input: { first: data.topics.pageInfo.total },
});
- 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',
- }),
+ const messages = {
+ loading: {
+ thematicsList: intl.formatMessage({
+ defaultMessage: 'Thematics are loading...',
+ description: 'SearchPage: loading thematics message',
+ id: 'qFqWQH',
+ }),
+ topicsList: intl.formatMessage({
+ defaultMessage: 'Topics are loading...',
+ description: 'SearchPage: loading topics message',
+ id: 'tLflgC',
+ }),
+ },
+ pageTitle: query.s
+ ? intl.formatMessage(
+ {
+ defaultMessage: 'Search results for "{query}"',
+ description: 'SearchPage: SEO - Page title',
+ id: 'N+3eau',
},
- validator: (value) => value.query.length > 1,
- };
+ { query: query.s as string }
+ )
+ : intl.formatMessage({
+ defaultMessage: 'Search',
+ description: 'SearchPage: SEO - Page title',
+ id: 'WDwNDl',
+ }),
+ seo: {
+ metaDesc: query.s
+ ? intl.formatMessage(
+ {
+ defaultMessage:
+ 'Discover search results for {query} on {websiteName}.',
+ description: 'SearchPage: SEO - Meta description',
+ id: 'pg26sn',
+ },
+ { query: query.s as string, websiteName: CONFIG.name }
+ )
+ : intl.formatMessage(
+ {
+ defaultMessage: 'Search for a post on {websiteName}.',
+ description: 'SearchPage: SEO - Meta description',
+ id: 'npisb3',
+ },
+ { websiteName: CONFIG.name }
+ ),
+ title: query.s
+ ? intl.formatMessage(
+ {
+ defaultMessage: 'Search results for {query} - {websiteName}',
+ description: 'SearchPage: SEO - Page title',
+ id: 'QRDdye',
+ },
+ { query: query.s as string, websiteName: CONFIG.name }
+ )
+ : intl.formatMessage(
+ {
+ defaultMessage: 'Search - {websiteName}',
+ description: 'SearchPage: SEO - Page title',
+ id: 'NqVQYo',
+ },
+ { websiteName: CONFIG.name }
+ ),
+ },
+ widgets: {
+ thematicsListTitle: intl.formatMessage({
+ defaultMessage: 'Thematics',
+ description: 'SearchPage: thematics list widget title',
+ id: 'Dq6+WH',
+ }),
+ topicsListTitle: intl.formatMessage({
+ defaultMessage: 'Topics',
+ description: 'SearchPage: topics list widget title',
+ id: 'N804XO',
+ }),
+ },
+ };
- routerPush({ pathname: ROUTES.SEARCH, query: { s: searchQuery } });
+ const { items: breadcrumbItems, schema: breadcrumbSchema } = useBreadcrumb({
+ title: messages.pageTitle,
+ url: ROUTES.SEARCH,
+ });
- return undefined;
- },
- [intl, routerPush]
- );
+ const webpageSchema = getWebPageSchema({
+ description: messages.seo.metaDesc,
+ locale: CONFIG.locales.defaultLocale,
+ slug: asPath,
+ title: messages.pageTitle,
+ });
+ const blogSchema = getBlogSchema({
+ isSinglePage: false,
+ locale: CONFIG.locales.defaultLocale,
+ slug: asPath,
+ });
+ const schemaJsonLd = getSchemaJson([webpageSchema, blogSchema]);
- const foundArticles = articles?.flatMap((p) =>
- p.edges.map((edge) => edge.node)
- );
+ const pageUrl = `${CONFIG.url}${asPath}`;
return (
<Page breadcrumbs={breadcrumbItems} isBodyLastChild>
<Head>
- <title>{page.title}</title>
+ <title>{messages.seo.title}</title>
{/*eslint-disable-next-line react/jsx-no-literals -- Name allowed */}
- <meta name="description" content={pageDescription} />
- <meta property="og:url" content={page.url} />
+ <meta name="description" content={messages.seo.metaDesc} />
+ <meta property="og:url" content={pageUrl} />
{/*eslint-disable-next-line react/jsx-no-literals -- Content allowed */}
<meta property="og:type" content="website" />
- <meta property="og:title" content={title} />
- <meta property="og:description" content={pageDescription} />
+ <meta property="og:title" content={messages.pageTitle} />
+ <meta property="og:description" content={messages.seo.title} />
</Head>
<Script
// eslint-disable-next-line react/jsx-no-literals -- Id allowed
@@ -205,36 +256,32 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
id="schema-breadcrumb"
type="application/ld+json"
/>
- <PageHeader heading={title} meta={{ total: totalArticles }} />
- <PageBody className={styles.body}>
- {foundArticles ? null : <Spinner>{loadingResults}</Spinner>}
- {foundArticles?.length ? (
+ <PageHeader
+ heading={messages.pageTitle}
+ meta={{ total: articles ? articles[0].pageInfo.total : undefined }}
+ />
+ <PageBody>
+ {query.s &&
+ ((articles?.length && articles[0].edges.length) || isLoading) ? (
<PostsList
- className={styles.list}
+ className={styles['posts-list']}
firstNewResult={firstNewResultIndex}
isLoading={isLoading || isLoadingMore || isRefreshing}
onLoadMore={hasNextPage ? loadMore : undefined}
- posts={getPostsWithUrl(foundArticles)}
+ posts={
+ articles
+ ? getPostsWithUrl(
+ articles.flatMap((page) =>
+ page.edges.map((edge) => edge.node)
+ )
+ )
+ : []
+ }
sortByYear
+ total={articles ? articles[0].pageInfo.total : undefined}
/>
) : (
- <>
- <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} />
- </>
+ <NoResults />
)}
{error ? (
<Notice
@@ -250,26 +297,34 @@ const SearchPage: NextPageWithLayout<SearchPageProps> = ({
) : null}
</PageBody>
<PageSidebar>
- <LinksWidget
- heading={
- <Heading isFake level={3}>
- {thematicsListTitle}
- </Heading>
- }
- items={getLinksItemData(
- thematicsList.map(convertWPThematicPreviewToPageLink)
- )}
- />
- <LinksWidget
- heading={
- <Heading isFake level={3}>
- {topicsListTitle}
- </Heading>
- }
- items={getLinksItemData(
- topicsList.map(convertWPTopicPreviewToPageLink)
- )}
- />
+ {areThematicsLoading ? (
+ <Spinner>{messages.loading.thematicsList}</Spinner>
+ ) : (
+ <LinksWidget
+ heading={
+ <Heading level={2}>{messages.widgets.thematicsListTitle}</Heading>
+ }
+ items={getLinksItemData(
+ thematics.edges.map((edge) =>
+ convertWPThematicPreviewToPageLink(edge.node)
+ )
+ )}
+ />
+ )}
+ {areTopicsLoading ? (
+ <Spinner>{messages.loading.topicsList}</Spinner>
+ ) : (
+ <LinksWidget
+ heading={
+ <Heading level={2}>{messages.widgets.topicsListTitle}</Heading>
+ }
+ items={getLinksItemData(
+ topics.edges.map((edge) =>
+ convertWPTopicPreviewToPageLink(edge.node)
+ )
+ )}
+ />
+ )}
</PageSidebar>
</Page>
);
@@ -288,8 +343,10 @@ export const getStaticProps: GetStaticProps<SearchPageProps> = async ({
return {
props: {
- thematicsList: thematics.edges.map((edge) => edge.node),
- topicsList: topics.edges.map((edge) => edge.node),
+ data: {
+ thematics,
+ topics,
+ },
translation,
},
};