aboutsummaryrefslogtreecommitdiffstats
path: root/src/pages/projets/index.tsx
blob: 97963ddceec874e67cab7225da424d852c38257a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import type { MDXComponents } from 'mdx/types';
import type { GetStaticProps } from 'next';
import Head from 'next/head';
import { useRouter } from 'next/router';
import Script from 'next/script';
import {
  CardsList,
  type CardsListItem,
  getLayout,
  Link,
  PageLayout,
} from '../../components';
import PageContent, { meta } from '../../content/pages/projects.mdx';
import styles from '../../styles/pages/projects.module.scss';
import type { NextPageWithLayout, ProjectCard } from '../../types';
import { ROUTES } from '../../utils/constants';
import {
  getSchemaJson,
  getSinglePageSchema,
  getWebPageSchema,
} from '../../utils/helpers';
import {
  getProjectsCard,
  loadTranslation,
  type Messages,
} from '../../utils/helpers/server';
import { useBreadcrumb, useSettings } from '../../utils/hooks';

const components: MDXComponents = {
  Link,
};

type ProjectsPageProps = {
  projects: ProjectCard[];
  translation?: Messages;
};

/**
 * Projects page.
 */
const ProjectsPage: NextPageWithLayout<ProjectsPageProps> = ({ projects }) => {
  const { dates, seo, title } = meta;
  const { items: breadcrumbItems, schema: breadcrumbSchema } = useBreadcrumb({
    title,
    url: ROUTES.PROJECTS,
  });

  const items: CardsListItem[] = projects.map(
    ({ id, meta: projectMeta, slug, title: projectTitle }) => {
      const { cover, tagline, technologies } = projectMeta;

      return {
        cover,
        id: id as string,
        meta: { technologies },
        tagline,
        title: projectTitle,
        url: `${ROUTES.PROJECTS}/${slug}`,
      };
    }
  );

  const { website } = useSettings();
  const { asPath } = useRouter();
  const webpageSchema = getWebPageSchema({
    description: seo.description,
    locale: website.locales.default,
    slug: asPath,
    title: seo.title,
    updateDate: dates.update,
  });
  const articleSchema = getSinglePageSchema({
    dates,
    description: seo.description,
    id: 'projects',
    kind: 'page',
    locale: website.locales.default,
    slug: asPath,
    title,
  });
  const schemaJsonLd = getSchemaJson([webpageSchema, articleSchema]);
  const page = {
    title: `${seo.title} - ${website.name}`,
    url: `${website.url}${asPath}`,
  };

  return (
    <>
      <Head>
        <title>{page.title}</title>
        {/*eslint-disable-next-line react/jsx-no-literals -- Name allowed */}
        <meta name="description" content={seo.description} />
        <meta property="og:url" content={page.url} />
        {/*eslint-disable-next-line react/jsx-no-literals -- Content allowed */}
        <meta property="og:type" content="article" />
        <meta property="og:title" content={page.title} />
        <meta property="og:description" content={seo.description} />
      </Head>
      <Script
        // eslint-disable-next-line react/jsx-no-literals -- Id allowed
        id="schema-projects"
        type="application/ld+json"
        // eslint-disable-next-line react/no-danger -- Necessary for schema
        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }}
      />
      <PageLayout
        title={title}
        intro={<PageContent components={components} />}
        breadcrumb={breadcrumbItems}
        breadcrumbSchema={breadcrumbSchema}
      >
        <CardsList items={items} titleLevel={2} className={styles.list} />
      </PageLayout>
    </>
  );
};

ProjectsPage.getLayout = (page) =>
  getLayout(page, { useGrid: true, withExtraPadding: true });

export const getStaticProps: GetStaticProps<ProjectsPageProps> = async ({
  locale,
}) => {
  const projects = await getProjectsCard();
  const translation = await loadTranslation(locale);

  return {
    props: {
      projects: JSON.parse(JSON.stringify(projects)),
      translation,
    },
  };
};

export default ProjectsPage;
ariaLabel = 'expedita repellat rem'; const total = 3; render( <Pagination aria-label={ariaLabel} current={total} renderItemAriaLabel={renderItemAriaLabel} renderLink={renderLink} total={total} /> ); expect( rtlScreen.getByRole('link', { name: backwardLabel }) ).toBeInTheDocument(); // the pages links + the backward link expect(rtlScreen.getAllByRole('listitem')).toHaveLength(total + 1); }); it('can skip next pages when the total is high and first page is selected', () => { const ariaLabel = 'expedita repellat rem'; const current = 1; const total = 50; /* * First page & the two next pages + 1 ellipsis + last page + forward link */ const expectedItemsCount = 6; render( <Pagination aria-label={ariaLabel} current={current} renderItemAriaLabel={renderItemAriaLabel} renderLink={renderLink} total={total} /> ); expect(rtlScreen.getAllByRole('listitem')).toHaveLength(expectedItemsCount); // The current page and the ellipsis should not be linked. expect(rtlScreen.getAllByRole('link')).toHaveLength(expectedItemsCount - 2); }); it('can skip previous pages when the total is high and last page is selected', () => { const ariaLabel = 'expedita repellat rem'; const current = 50; const total = 50; /* * Last page & the two previous pages + 1 ellipsis + first page + backward * link */ const expectedItemsCount = 6; render( <Pagination aria-label={ariaLabel} current={current} renderItemAriaLabel={renderItemAriaLabel} renderLink={renderLink} total={total} /> ); expect(rtlScreen.getAllByRole('listitem')).toHaveLength(expectedItemsCount); // The current page and the ellipsis should not be linked. expect(rtlScreen.getAllByRole('link')).toHaveLength(expectedItemsCount - 2); }); it('can render a custom number of siblings', () => { const ariaLabel = 'expedita repellat rem'; const siblings = 3; const current = 10; const total = 20; /* * Current page + 3 siblings on each side + first page + last page + 2 * ellipsis + backward and forward links */ const expectedItemsCount = 13; render( <Pagination aria-label={ariaLabel} current={current} renderItemAriaLabel={renderItemAriaLabel} renderLink={renderLink} siblings={siblings} total={total} /> ); expect(rtlScreen.getAllByRole('listitem')).toHaveLength(expectedItemsCount); /* eslint-disable-next-line @typescript-eslint/no-magic-numbers -- The current page and the two ellipsis should not be linked. */ expect(rtlScreen.getAllByRole('link')).toHaveLength(expectedItemsCount - 3); }); });