From e9d5a40432c451090e17859c764e52a96120b712 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Mon, 4 Dec 2023 19:36:34 +0100 Subject: refactor(pages): refine Search page * extract NoResults component to improve readability * provide a different message when the url does not contain a query * use hooks to refresh Thematics and Topics lists * remove useDataFromApi hook --- src/pages/recherche/index.tsx | 365 ++++++++++++++++++++++++------------------ 1 file changed, 211 insertions(+), 154 deletions(-) (limited to 'src/pages/recherche/index.tsx') 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 ( +
+

+ {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', + })} +

+ +
+ ); +}; + type SearchPageProps = { - thematicsList: WPThematicPreview[]; - topicsList: WPTopicPreview[]; + data: { + thematics: GraphQLConnection; + topics: GraphQLConnection; + }; translation: Messages; }; /** * Search page. */ -const SearchPage: NextPageWithLayout = ({ - thematicsList, - topicsList, -}) => { +const SearchPage: NextPageWithLayout = ({ 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 = ({ hasNextPage, loadMore, } = useArticlesList({ - fallback: [], perPage: CONFIG.postsPerPage, - searchQuery: query.s as string, + searchQuery: typeof query.s === 'string' ? query.s : undefined, }); - - const totalArticles = useDataFromAPI(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.title} + {messages.seo.title} {/*eslint-disable-next-line react/jsx-no-literals -- Name allowed */} - - + + {/*eslint-disable-next-line react/jsx-no-literals -- Content allowed */} - - + +