From 7e16f500cb7bc0cfd8bafbf6bb1555704f771231 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 29 Apr 2022 12:13:34 +0200 Subject: chore: remove old pages, components, helpers and types Since I'm using new components, I will also rewrite the GraphQL queries so it is easier to start from scratch. --- src/pages/404.tsx | 85 ------------------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 src/pages/404.tsx (limited to 'src/pages/404.tsx') diff --git a/src/pages/404.tsx b/src/pages/404.tsx deleted file mode 100644 index 24c6951..0000000 --- a/src/pages/404.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { getLayout } from '@components/Layouts/Layout'; -import PostHeader from '@components/PostHeader/PostHeader'; -import styles from '@styles/pages/Page.module.scss'; -import { NextPageWithLayout } from '@ts/types/app'; -import { settings } from '@utils/config'; -import { getIntlInstance, loadTranslation } from '@utils/helpers/i18n'; -import { GetStaticProps, GetStaticPropsContext } from 'next'; -import Head from 'next/head'; -import Link from 'next/link'; -import { FormattedMessage, useIntl } from 'react-intl'; - -const Error404: NextPageWithLayout = () => { - const intl = useIntl(); - - const pageTitle = intl.formatMessage( - { - defaultMessage: 'Error 404: Page not found - {websiteName}', - description: '404Page: SEO - Page title', - id: '310o3F', - }, - { websiteName: settings.name } - ); - const pageDescription = intl.formatMessage({ - defaultMessage: 'Page not found.', - description: '404Page: SEO - Meta description', - id: '48Ww//', - }); - - return ( - <> - - {pageTitle} - - -
- -
- ( - - {chunks} - - ), - }} - /> -
-
- - ); -}; - -Error404.getLayout = getLayout; - -export const getStaticProps: GetStaticProps = async ( - context: GetStaticPropsContext -) => { - const intl = await getIntlInstance(); - const breadcrumbTitle = intl.formatMessage({ - defaultMessage: 'Error 404', - description: '404Page: breadcrumb item', - id: 'ywkCsK', - }); - const { locale } = context; - const translation = await loadTranslation(locale); - - return { - props: { - breadcrumbTitle, - locale, - translation, - }, - }; -}; - -export default Error404; -- cgit v1.2.3 From 8a55aa83bd4b64d1d989cb49b7d9c3fdc1cc6ea5 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Mon, 16 May 2022 11:37:09 +0200 Subject: chore: add 404 page --- src/pages/404.tsx | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/pages/404.tsx (limited to 'src/pages/404.tsx') diff --git a/src/pages/404.tsx b/src/pages/404.tsx new file mode 100644 index 0000000..7459c80 --- /dev/null +++ b/src/pages/404.tsx @@ -0,0 +1,144 @@ +import Link from '@components/atoms/links/link'; +import { type BreadcrumbItem } from '@components/molecules/nav/breadcrumb'; +import LinksListWidget from '@components/organisms/widgets/links-list-widget'; +import PageLayout from '@components/templates/page/page-layout'; +import { + getThematicsPreview, + getTotalThematics, +} from '@services/graphql/thematics'; +import { getTopicsPreview, getTotalTopics } from '@services/graphql/topics'; +import { + type RawThematicPreview, + type RawTopicPreview, +} from '@ts/types/raw-data'; +import { loadTranslation, type Messages } from '@utils/helpers/i18n'; +import { + getLinksListItems, + getPageLinkFromRawData, +} from '@utils/helpers/pages'; +import useSettings from '@utils/hooks/use-settings'; +import { GetStaticProps, NextPage } from 'next'; +import Head from 'next/head'; +import { ReactNode } from 'react'; +import { useIntl } from 'react-intl'; + +type Error404PageProps = { + thematicsList: RawThematicPreview[]; + topicsList: RawTopicPreview[]; + translation: Messages; +}; + +/** + * Error 404 page. + */ +const Error404Page: NextPage = ({ + thematicsList, + topicsList, +}) => { + const intl = useIntl(); + const { website } = useSettings(); + const title = intl.formatMessage({ + defaultMessage: 'Page not found', + description: 'Error404Page: page title', + id: 'KnWeKh', + }); + const body = intl.formatMessage( + { + defaultMessage: + 'Sorry, it seems that the page your are looking for does not exist. If you think this path should work, feel free to contact me with the necessary information so that I can fix the problem.', + id: '9sGNKq', + description: 'Error404Page: page body', + }, + { + link: (chunks: ReactNode) => {chunks}, + } + ); + const homeLabel = intl.formatMessage({ + defaultMessage: 'Home', + description: 'Breadcrumb: home label', + id: 'j5k9Fe', + }); + const breadcrumb: BreadcrumbItem[] = [ + { id: 'home', name: homeLabel, url: '/' }, + { id: 'error-404', name: title, url: '/404' }, + ]; + const pageTitle = intl.formatMessage( + { + defaultMessage: 'Error 404: Page not found - {websiteName}', + description: '404Page: SEO - Page title', + id: '310o3F', + }, + { websiteName: website.name } + ); + const pageDescription = intl.formatMessage({ + defaultMessage: 'Page not found.', + description: '404Page: SEO - Meta description', + id: '48Ww//', + }); + const thematicsListTitle = intl.formatMessage({ + defaultMessage: 'Thematics', + description: 'Error404Page: thematics list widget title', + id: 'HohQPh', + }); + + const topicsListTitle = intl.formatMessage({ + defaultMessage: 'Topics', + description: 'Error404Page: topics list widget title', + id: 'GVpTIl', + }); + + return ( + <> + + {pageTitle} + + + , + , + ]} + > + {body} + + + ); +}; + +export const getStaticProps: GetStaticProps = async ({ + locale, +}) => { + const totalThematics = await getTotalThematics(); + const thematics = await getThematicsPreview({ first: totalThematics }); + const totalTopics = await getTotalTopics(); + const topics = await getTopicsPreview({ first: totalTopics }); + const translation = await loadTranslation(locale); + + return { + props: { + thematicsList: thematics.edges.map((edge) => edge.node), + topicsList: topics.edges.map((edge) => edge.node), + translation, + }, + }; +}; + +export default Error404Page; -- cgit v1.2.3 From 2155550fa36a3bc3c8f66e0926530123b4018cd4 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Mon, 16 May 2022 12:46:38 +0200 Subject: refactor: use custom hook for breadcrumb items and schema --- src/components/templates/layout/layout.stories.tsx | 54 ++++++++--- src/components/templates/layout/layout.test.tsx | 12 ++- src/components/templates/layout/layout.tsx | 26 ++++- .../templates/page/page-layout.stories.tsx | 12 +++ src/components/templates/page/page-layout.test.tsx | 41 ++++++-- src/components/templates/page/page-layout.tsx | 11 ++- .../sectioned/sectioned-layout.stories.tsx | 24 +++-- .../templates/sectioned/sectioned-layout.test.tsx | 9 +- .../templates/sectioned/sectioned-layout.tsx | 8 +- src/pages/404.tsx | 16 ++-- src/pages/article/[slug].tsx | 24 ++--- src/pages/blog/index.tsx | 16 ++-- src/pages/contact.tsx | 22 ++--- src/pages/cv.tsx | 22 ++--- src/pages/index.tsx | 9 +- src/pages/mentions-legales.tsx | 22 ++--- src/pages/projets/[slug].tsx | 27 ++---- src/pages/projets/index.tsx | 22 ++--- src/pages/recherche/index.tsx | 22 ++--- src/pages/sujet/[slug].tsx | 22 ++--- src/pages/thematique/[slug].tsx | 22 ++--- src/utils/hooks/use-breadcrumb.tsx | 106 +++++++++++++++++++++ 22 files changed, 343 insertions(+), 206 deletions(-) create mode 100644 src/utils/hooks/use-breadcrumb.tsx (limited to 'src/pages/404.tsx') diff --git a/src/components/templates/layout/layout.stories.tsx b/src/components/templates/layout/layout.stories.tsx index 2415412..105e808 100644 --- a/src/components/templates/layout/layout.stories.tsx +++ b/src/components/templates/layout/layout.stories.tsx @@ -1,5 +1,4 @@ import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { IntlProvider } from 'react-intl'; import LayoutComponent from './layout'; /** @@ -8,6 +7,10 @@ import LayoutComponent from './layout'; export default { title: 'Templates/LayoutBase', component: LayoutComponent, + args: { + breadcrumbSchema: [], + isHome: false, + }, argTypes: { children: { control: { @@ -19,6 +22,31 @@ export default { required: true, }, }, + breadcrumbSchema: { + control: { + type: 'null', + }, + description: 'The JSON schema for breadcrumb items.', + type: { + name: 'object', + required: true, + value: {}, + }, + }, + isHome: { + control: { + type: 'boolean', + }, + description: 'Determine if it is the homepage.', + table: { + category: 'Options', + defaultValue: { summary: false }, + }, + type: { + name: 'boolean', + required: false, + }, + }, className: { control: { type: 'text', @@ -35,19 +63,17 @@ export default { }, decorators: [ (Story) => ( - -
- -
-
+
+ +
), ], parameters: { diff --git a/src/components/templates/layout/layout.test.tsx b/src/components/templates/layout/layout.test.tsx index 914e1cd..94145ec 100644 --- a/src/components/templates/layout/layout.test.tsx +++ b/src/components/templates/layout/layout.test.tsx @@ -1,34 +1,36 @@ import { render, screen } from '@test-utils'; +import { BreadcrumbList } from 'schema-dts'; import Layout from './layout'; const body = 'Sit dolorem eveniet. Sit sit odio nemo vitae corrupti modi sint est rerum. Pariatur quidem maiores distinctio. Quia et illum aspernatur est cum.'; +const breadcrumbSchema: BreadcrumbList['itemListElement'][] = []; describe('Layout', () => { it('renders the website header', () => { - render({body}); + render({body}); expect(screen.getByRole('banner')).toBeInTheDocument(); }); it('renders the website main content', () => { - render({body}); + render({body}); expect(screen.getByRole('main')).toBeInTheDocument(); }); it('renders the website footer', () => { - render({body}); + render({body}); expect(screen.getByRole('contentinfo')).toBeInTheDocument(); }); it('renders a skip to content link', () => { - render({body}); + render({body}); expect( screen.getByRole('link', { name: 'Skip to content' }) ).toBeInTheDocument(); }); it('renders an article', () => { - render({body}); + render({body}); expect(screen.getByRole('article')).toHaveTextContent(body); }); }); diff --git a/src/components/templates/layout/layout.tsx b/src/components/templates/layout/layout.tsx index bfb918b..9e9282b 100644 --- a/src/components/templates/layout/layout.tsx +++ b/src/components/templates/layout/layout.tsx @@ -13,7 +13,13 @@ import useSettings from '@utils/hooks/use-settings'; import Script from 'next/script'; import { FC, ReactNode } from 'react'; import { useIntl } from 'react-intl'; -import { Person, SearchAction, WebSite, WithContext } from 'schema-dts'; +import { + BreadcrumbList, + Person, + SearchAction, + WebSite, + WithContext, +} from 'schema-dts'; import styles from './layout.module.scss'; export type QueryAction = SearchAction & { @@ -21,6 +27,10 @@ export type QueryAction = SearchAction & { }; export type LayoutProps = Pick & { + /** + * The breadcrumb JSON schema. + */ + breadcrumbSchema: BreadcrumbList['itemListElement'][]; /** * The layout main content. */ @@ -36,7 +46,12 @@ export type LayoutProps = Pick & { * * Render the base layout used by all pages. */ -const Layout: FC = ({ children, isHome, ...props }) => { +const Layout: FC = ({ + breadcrumbSchema, + children, + isHome, + ...props +}) => { const intl = useIntl(); const { website } = useSettings(); const { baseline, copyright, locales, name, picture, url } = website; @@ -153,12 +168,17 @@ const Layout: FC = ({ children, isHome, ...props }) => { id="schema-layout" type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }} - > + />