summaryrefslogtreecommitdiffstats
path: root/src/components/molecules/nav/breadcrumb.tsx
blob: 6dc86a05fb2026610cd63dae15feb15de21d197b (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
import Link from '@components/atoms/links/link';
import { settings } from '@utils/config';
import Script from 'next/script';
import { FC } from 'react';
import { useIntl } from 'react-intl';
import { BreadcrumbList, ListItem, WithContext } from 'schema-dts';
import styles from './breadcrumb.module.scss';

export type BreadcrumbItem = {
  /**
   * The item id.
   */
  id: string;
  /**
   * The item URL.
   */
  url: string;
  /**
   * The item name.
   */
  name: string;
};

export type BreadcrumbProps = {
  /**
   * Set additional classnames to the nav element.
   */
  className?: string;
  /**
   * The breadcrumb items
   */
  items: BreadcrumbItem[];
};

/**
 * Breadcrumb component
 *
 * Render a breadcrumb navigation.
 */
const Breadcrumb: FC<BreadcrumbProps> = ({ items, ...props }) => {
  const intl = useIntl();

  /**
   * Retrieve the breadcrumb list items.
   *
   * @param {BreadcrumbItem[]} list - The breadcrumb items.
   * @returns {JSX.Element[]} The list items.
   */
  const getListItems = (list: BreadcrumbItem[]): JSX.Element[] => {
    return list.map((item, index) => {
      const isLastItem = index === list.length - 1;
      const itemClassnames = isLastItem
        ? `${styles.item} screen-reader-text`
        : styles.item;

      return (
        <li key={item.id} className={itemClassnames}>
          {isLastItem ? item.name : <Link href={item.url}>{item.name}</Link>}
        </li>
      );
    });
  };

  /**
   * Retrieve the breadcrumb list items with Schema.org format.
   *
   * @param {BreadcrumbItem[]} list - The breadcrumb items.
   * @returns {ListItem[]} An array of list items using Schema.org format.
   */
  const getSchemaItems = (list: BreadcrumbItem[]): ListItem[] => {
    const schemaItems: ListItem[] = [];

    list.forEach((item, index) => {
      schemaItems.push({
        '@type': 'ListItem',
        position: index + 1,
        name: item.name,
        item: item.url,
      });
    });

    return schemaItems;
  };

  const schemaJsonLd: WithContext<BreadcrumbList> = {
    '@context': 'https://schema.org',
    '@type': 'BreadcrumbList',
    '@id': `${settings.url}/#breadcrumb`,
    itemListElement: getSchemaItems(items),
  };

  return (
    <>
      <Script
        id="schema-breadcrumb"
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }}
      />
      <nav {...props}>
        <span className="screen-reader-text">
          {intl.formatMessage({
            defaultMessage: 'You are here:',
            description: 'Breadcrumb: You are here prefix',
            id: '16zl9Z',
          })}
        </span>
        <ol className={styles.list}>{getListItems(items)}</ol>
      </nav>
    </>
  );
};

export default Breadcrumb;