From dfdbf6cac1fe3719dc71e130129d28e04ba4e225 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 1 Dec 2023 13:26:44 +0100 Subject: refactor(pages): refine Thematic pages * add a table of contents (however posts heading are not included) * rename posts list section title * add a useThematic hook to refresh thematic contents * add a useThematicLists hook to refresh thematics list * add a `notIn` filter in thematics list fetcher to directly remove unwanted thematics * add Cypress tests --- src/pages/sujet/[slug].tsx | 2 +- src/pages/thematique/[slug].tsx | 181 ++++++++++++++++++++++++++-------------- 2 files changed, 120 insertions(+), 63 deletions(-) (limited to 'src/pages') diff --git a/src/pages/sujet/[slug].tsx b/src/pages/sujet/[slug].tsx index 483df48..185756b 100644 --- a/src/pages/sujet/[slug].tsx +++ b/src/pages/sujet/[slug].tsx @@ -97,7 +97,7 @@ const TopicPage: NextPageWithLayout = ({ const getPageHeading = () => ( <> - {cover ? : null} + {cover ? : null} {title} ); diff --git a/src/pages/thematique/[slug].tsx b/src/pages/thematique/[slug].tsx index 487b18b..e290782 100644 --- a/src/pages/thematique/[slug].tsx +++ b/src/pages/thematique/[slug].tsx @@ -14,17 +14,24 @@ import { PageHeader, PageSidebar, PageBody, + LoadingPage, + TocWidget, + Spinner, } from '../../components'; import { convertWPThematicPreviewToPageLink, - convertWPThematicToThematic, fetchAllThematicsSlugs, fetchThematic, fetchThematicsCount, fetchThematicsList, } from '../../services/graphql'; import styles from '../../styles/pages/blog.module.scss'; -import type { NextPageWithLayout, PageLink, Thematic } from '../../types'; +import type { + GraphQLConnection, + NextPageWithLayout, + WPThematic, + WPThematicPreview, +} from '../../types'; import { CONFIG } from '../../utils/config'; import { ROUTES } from '../../utils/constants'; import { @@ -33,29 +40,47 @@ import { getSchemaJson, getSinglePageSchema, getWebPageSchema, + slugify, } from '../../utils/helpers'; import { loadTranslation, type Messages } from '../../utils/helpers/server'; -import { useBreadcrumb } from '../../utils/hooks'; +import { + useBreadcrumb, + useHeadingsTree, + useThematic, + useThematicsList, +} from '../../utils/hooks'; export type ThematicPageProps = { - currentThematic: Thematic; - thematics: PageLink[]; + data: { + currentThematic: WPThematic; + otherThematics: GraphQLConnection; + totalThematics: number; + }; translation: Messages; }; -const ThematicPage: NextPageWithLayout = ({ - currentThematic, - thematics, -}) => { - const { content, intro, meta, slug, title } = currentThematic; - const { articles, dates, seo, relatedTopics } = meta; +const ThematicPage: NextPageWithLayout = ({ data }) => { const intl = useIntl(); + const { isFallback } = useRouter(); + const { isLoading, thematic } = useThematic( + data.currentThematic.slug, + data.currentThematic + ); + const { isLoading: areThematicsLoading, thematics } = useThematicsList({ + fallback: data.otherThematics, + input: { first: data.totalThematics, where: { notIn: [thematic.id] } }, + }); const { items: breadcrumbItems, schema: breadcrumbSchema } = useBreadcrumb({ - title, - url: `${ROUTES.THEMATICS}/${slug}`, + title: data.currentThematic.title, + url: `${ROUTES.THEMATICS}/${data.currentThematic.slug}`, }); + const { ref, tree } = useHeadingsTree({ fromLevel: 2 }); + + if (isFallback || isLoading) return ; + + const { content, intro, meta, slug, title } = thematic; + const { articles, dates, seo, relatedTopics } = meta; - const { asPath } = useRouter(); const webpageSchema = getWebPageSchema({ description: seo.description, locale: CONFIG.locales.defaultLocale, @@ -74,18 +99,41 @@ const ThematicPage: NextPageWithLayout = ({ }); const schemaJsonLd = getSchemaJson([webpageSchema, articleSchema]); - const thematicsListTitle = intl.formatMessage({ - defaultMessage: 'Other thematics', - description: 'ThematicPage: other thematics list widget title', - id: 'KVSWGP', - }); + const messages = { + widgets: { + loadingThematicsList: intl.formatMessage({ + defaultMessage: 'Thematics are loading...', + description: 'ThematicPage: loading thematics message', + id: 'rVoW4G', + }), + thematicsListTitle: intl.formatMessage({ + defaultMessage: 'Other thematics', + description: 'ThematicPage: other thematics list widget title', + id: 'KVSWGP', + }), + tocTitle: intl.formatMessage({ + defaultMessage: 'Table of Contents', + description: 'PageLayout: table of contents title', + id: 'eys2uX', + }), + topicsListTitle: intl.formatMessage({ + defaultMessage: 'Related topics', + description: 'ThematicPage: related topics list widget title', + id: '/42Z0z', + }), + }, + browsePostsTitle: intl.formatMessage( + { + defaultMessage: 'Browse posts in {thematicName} thematic', + description: 'ThematicPage: posts list heading', + id: 'jrRBeb', + }, + { thematicName: title } + ), + }; - const topicsListTitle = intl.formatMessage({ - defaultMessage: 'Related topics', - description: 'ThematicPage: related topics list widget title', - id: '/42Z0z', - }); - const pageUrl = `${CONFIG.url}${asPath}`; + const pageUrl = `${CONFIG.url}${slug}`; + const browsePostHeadingId = slugify(messages.browsePostsTitle); return ( @@ -121,23 +169,33 @@ const ThematicPage: NextPageWithLayout = ({ updateDate: dates.update, }} /> - - {/*eslint-disable-next-line react/no-danger -- Necessary for content*/} -
+ + {messages.widgets.tocTitle}} + tree={[ + ...tree, + { + children: [], + depth: 2, + id: browsePostHeadingId, + label: messages.browsePostsTitle, + }, + ]} + /> + + +
{articles ? ( <> - - {intl.formatMessage( - { - defaultMessage: 'All posts in {thematicName}', - description: 'ThematicPage: posts list heading', - id: 'LszkU6', - }, - { thematicName: title } - )} + + {messages.browsePostsTitle} = ({ ) : null} - - {thematicsListTitle} - - } - items={getLinksItemData(thematics)} - /> + {areThematicsLoading ? ( + {messages.widgets.loadingThematicsList} + ) : ( + {messages.widgets.thematicsListTitle} + } + items={getLinksItemData( + thematics.edges.map((edge) => + convertWPThematicPreviewToPageLink(edge.node) + ) + )} + /> + )} {relatedTopics ? ( - {topicsListTitle} - + {messages.widgets.topicsListTitle} } items={getLinksItemData(relatedTopics)} /> @@ -179,26 +241,21 @@ export const getStaticProps: GetStaticProps = async ({ locale, params, }) => { - const currentThematic = await fetchThematic((params as ThematicParams).slug); + const thematic = await fetchThematic((params as ThematicParams).slug); const totalThematics = await fetchThematicsCount(); - const allThematicsEdges = await fetchThematicsList({ + const otherThematics = await fetchThematicsList({ first: totalThematics, + where: { notIn: [thematic.databaseId] }, }); - const allThematics = allThematicsEdges.edges.map((edge) => - convertWPThematicPreviewToPageLink(edge.node) - ); - const allThematicsLinks = allThematics.filter( - (thematic) => - thematic.url !== `${ROUTES.THEMATICS}/${(params as ThematicParams).slug}` - ); const translation = await loadTranslation(locale); return { props: { - currentThematic: JSON.parse( - JSON.stringify(convertWPThematicToThematic(currentThematic)) - ), - thematics: JSON.parse(JSON.stringify(allThematicsLinks)), + data: { + currentThematic: JSON.parse(JSON.stringify(thematic)), + otherThematics: JSON.parse(JSON.stringify(otherThematics)), + totalThematics, + }, translation, }, }; -- cgit v1.2.3