gatsby-core-theme 1.3.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.storybook/main.js +2 -3
  2. package/.storybook/preview.js +1 -4
  3. package/CHANGELOG.md +94 -0
  4. package/gatsby-node.esm.js +59 -19
  5. package/jest.config.js +1 -0
  6. package/package.json +1 -1
  7. package/src/components/app.js +12 -7
  8. package/src/components/atoms/archive/items/index.js +1 -1
  9. package/src/components/atoms/author/index.js +3 -2
  10. package/src/components/atoms/author-box/author-box.test.js +1 -5
  11. package/src/components/atoms/author-box/index.js +42 -13
  12. package/src/components/atoms/breadcrumbs/index.js +8 -4
  13. package/src/components/atoms/button/button.test.js +7 -0
  14. package/src/components/atoms/button/index.js +10 -3
  15. package/src/components/atoms/carousel/arrow/index.js +3 -2
  16. package/src/components/atoms/carousel/pagination-item/index.js +3 -2
  17. package/src/components/atoms/collapse/index.js +3 -1
  18. package/src/components/atoms/custom-select/index.js +2 -1
  19. package/src/components/atoms/logo/index.js +2 -2
  20. package/src/components/atoms/menu/items/index.js +6 -0
  21. package/src/components/atoms/menu/items/item/index.js +5 -4
  22. package/src/components/atoms/menu/menu-icon/index.js +4 -4
  23. package/src/components/atoms/module-title/index.js +2 -1
  24. package/src/components/atoms/not-found/index.js +14 -0
  25. package/src/components/atoms/not-found/not-found.module.scss +16 -0
  26. package/src/components/atoms/open-graph/index.js +5 -5
  27. package/src/components/atoms/operator-cta/index.js +15 -5
  28. package/src/components/atoms/operator-cta/{operator-cta.test.disabled.js → operator-cta.test.js} +12 -1
  29. package/src/components/atoms/operator-info-block/index.js +8 -1
  30. package/src/components/atoms/search/autocomplete/operator.js +1 -1
  31. package/src/components/atoms/spotlights/index.js +15 -4
  32. package/src/components/molecules/carousel/default-slide/index.js +4 -0
  33. package/src/components/molecules/counter/index.js +2 -2
  34. package/src/components/molecules/footer/index.js +6 -2
  35. package/src/components/molecules/header/header.test.js +0 -1
  36. package/src/components/molecules/link-list/index.js +9 -1
  37. package/src/components/molecules/main/index.js +3 -1
  38. package/src/components/molecules/menu/index.js +5 -1
  39. package/src/components/molecules/operator-banner/index.js +17 -7
  40. package/src/components/molecules/operator-banner/operator-banner.test.js +1 -1
  41. package/src/components/molecules/pagination/index.js +16 -5
  42. package/src/components/molecules/pagination/pagination.test.js +3 -3
  43. package/src/components/molecules/pagination/with-midpoints.js +41 -17
  44. package/src/components/molecules/pagination/with-midpoints.test.js +7 -8
  45. package/src/components/molecules/search/index.js +14 -3
  46. package/src/components/molecules/slider/index.js +27 -3
  47. package/src/components/molecules/toplist/default-row/index.js +27 -4
  48. package/src/components/organisms/accordion/accordion.test.js +3 -3
  49. package/src/components/organisms/accordion/index.js +1 -1
  50. package/src/components/organisms/anchor/index.js +2 -1
  51. package/src/components/organisms/archive/archive.test.js +8 -1
  52. package/src/components/organisms/archive/index.js +12 -12
  53. package/src/components/organisms/cards/cards.stories.js +1 -0
  54. package/src/components/organisms/cards/index.js +1 -1
  55. package/src/components/organisms/carousel/index.js +16 -17
  56. package/src/components/organisms/cookie-consent/cookie-consent.stories.js +6 -1
  57. package/src/components/organisms/cookie-consent/index.js +2 -0
  58. package/src/components/organisms/form/index.js +1 -0
  59. package/src/components/organisms/navigation/index.js +4 -4
  60. package/src/components/organisms/search/index.js +1 -1
  61. package/src/components/organisms/toplist/index.js +15 -19
  62. package/src/components/organisms/toplist/list/index.js +22 -29
  63. package/src/components/pages/body/index.js +9 -5
  64. package/src/components/pages/search/index.js +36 -1
  65. package/src/components/pages/tracker/index.js +8 -4
  66. package/src/constants/pick-keys.js +2 -0
  67. package/src/context/TranslationsProvider.js +9 -0
  68. package/src/helpers/processor/index.js +20 -3
  69. package/src/helpers/processor/processor.test.js +14 -0
  70. package/src/hooks/lazy-image/lazy-image.stories.js +1 -0
  71. package/src/hooks/link/index.js +2 -0
  72. package/src/hooks/link/link.test.js +9 -0
  73. package/src/hooks/modal/modal-content.js +7 -3
  74. package/src/hooks/modal/modal.test.js +3 -2
  75. package/src/hooks/tabs/index.js +4 -1
  76. package/src/hooks/tabs/tab/tab-list.js +4 -1
  77. package/src/hooks/tabs/tab/tab.js +11 -2
  78. package/src/pages/sitemap/index.js +77 -0
  79. package/src/pages/sitemap/sitemap.module.scss +21 -0
  80. package/tests/factories/relations/operator.factory.js +33 -0
@@ -30,7 +30,7 @@ const CustomSelect = ({
30
30
  <div className={styles.customSelectContainer}>
31
31
  <button
32
32
  ref={defBtn}
33
- className={styles.select}
33
+ className={`${styles.select} custom-select-gtm btn-cta`}
34
34
  type="button"
35
35
  onClick={showDropdown}
36
36
  data-id="select-button"
@@ -56,6 +56,7 @@ const CustomSelect = ({
56
56
  >
57
57
  <button
58
58
  type="button"
59
+ className="custom-select-gtm btn-cta"
59
60
  onClick={() => {
60
61
  onClick(currentItem[itemsValue], currentItem[itemsLabel], currentItem.type);
61
62
  setSelectedOption(currentItem);
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { prettyTracker,imagePrettyUrl } from '~helpers/getters';
3
+ import { prettyTracker, imagePrettyUrl } from '~helpers/getters';
4
4
  import LazyImage from '~hooks/lazy-image';
5
5
 
6
6
  import styles from './logo.module.scss';
@@ -11,7 +11,7 @@ const Logo = ({ item = {} }) => {
11
11
  return (
12
12
  <div>
13
13
  <a
14
- className={styles.operatorLogo}
14
+ className={`${styles.operatorLogo} logo-cta`}
15
15
  href={prettyLink}
16
16
  title={item.name}
17
17
  target="_blank"
@@ -1,3 +1,4 @@
1
+ /* eslint-disable arrow-body-style */
1
2
  import React, { useRef } from 'react';
2
3
  import PropTypes from 'prop-types';
3
4
  import Item from './item';
@@ -14,6 +15,7 @@ const Items = ({
14
15
  subMenuDropDownButton: true,
15
16
  },
16
17
  },
18
+ gtmClass = '',
17
19
  }) => {
18
20
  let link;
19
21
  let menu;
@@ -46,6 +48,7 @@ const Items = ({
46
48
  hasChildren
47
49
  item={item}
48
50
  showSubMenuHandler={showSubMenu}
51
+ gtmClass={gtmClass}
49
52
  options={{
50
53
  mobile: {
51
54
  subMenuDropDownButton: options.mobile.subMenuDropDownButton,
@@ -61,6 +64,7 @@ const Items = ({
61
64
  key={keygen()}
62
65
  item={child}
63
66
  menuListRef={menuListRef}
67
+ gtmClass={gtmClass}
64
68
  options={{
65
69
  mobile: {
66
70
  canOpenAllSubMenus: options.mobile.canOpenAllSubMenus,
@@ -77,6 +81,7 @@ const Items = ({
77
81
  <Item
78
82
  hasChildren={false}
79
83
  item={item}
84
+ gtmClass={gtmClass}
80
85
  options={{ mobile: { subMenuDropDownButton: options.mobile.subMenuDropDownButton } }}
81
86
  />
82
87
  );
@@ -108,6 +113,7 @@ Items.propTypes = {
108
113
  subMenuDropDownButton: PropTypes.bool,
109
114
  }),
110
115
  }),
116
+ gtmClass: PropTypes.string,
111
117
  };
112
118
 
113
119
  export default Items;
@@ -6,8 +6,6 @@ import ConditionalWrapper from '~atoms/conditional-wrapper';
6
6
 
7
7
  import styles from './item.module.scss';
8
8
 
9
- /* eslint-disable react/jsx-no-target-blank */
10
-
11
9
  export default function Item({
12
10
  item,
13
11
  hasChildren,
@@ -17,6 +15,7 @@ export default function Item({
17
15
  subMenuDropDownButton: true,
18
16
  },
19
17
  },
18
+ gtmClass = '',
20
19
  }) {
21
20
  const [active, setActive] = useState('');
22
21
  useEffect(() => {
@@ -51,7 +50,7 @@ export default function Item({
51
50
  title={item.title}
52
51
  rel={`noreferrer ${item.nofollow && 'nofollow'}`}
53
52
  target="_blank"
54
- className={`${styles.item} ${active} ${
53
+ className={`${gtmClass} ${styles.item} ${active} ${
55
54
  !options.mobile.subMenuDropDownButton && isMobile && hasChildren
56
55
  ? styles.inactiveLink
57
56
  : ''
@@ -63,7 +62,7 @@ export default function Item({
63
62
  </a>
64
63
  ) : (
65
64
  <Link
66
- className={`${styles.item} ${active} ${
65
+ className={`${gtmClass} ${styles.item} ${active} ${
67
66
  !options.mobile.subMenuDropDownButton && isMobile && hasChildren
68
67
  ? styles.inactiveLink
69
68
  : ''
@@ -80,6 +79,7 @@ export default function Item({
80
79
  {options.mobile.subMenuDropDownButton && isMobile && hasChildren && (
81
80
  <button
82
81
  type="button"
82
+ className={`${gtmClass} btn-cta`}
83
83
  onClick={(e) => {
84
84
  showSubMenuHandler(styles);
85
85
  toggleDropDown(e);
@@ -111,4 +111,5 @@ Item.propTypes = {
111
111
  subMenuDropDownButton: PropTypes.bool,
112
112
  }),
113
113
  }),
114
+ gtmClass: PropTypes.string,
114
115
  };
@@ -3,13 +3,12 @@ import PropTypes from 'prop-types';
3
3
  import { NavigationContext } from '~organisms/navigation/navigationContext';
4
4
  import styles from './menu-icon.module.scss';
5
5
 
6
- const MenuIcon = ({ onClick }) => {
7
-
6
+ const MenuIcon = ({ onClick, gtmClass }) => {
8
7
  const { showMenu } = useContext(NavigationContext);
9
8
 
10
9
  return (
11
10
  <div
12
- className={styles.menuIconContainer}
11
+ className={`${styles.menuIconContainer} ${gtmClass}`}
13
12
  onKeyDown={() => onClick()}
14
13
  onClick={() => onClick()}
15
14
  role="button"
@@ -24,7 +23,8 @@ const MenuIcon = ({ onClick }) => {
24
23
  };
25
24
 
26
25
  MenuIcon.propTypes = {
27
- onClick: PropTypes.func.isRequired
26
+ onClick: PropTypes.func.isRequired,
27
+ gtmClass: PropTypes.string,
28
28
  };
29
29
 
30
30
  export default MenuIcon;
@@ -36,7 +36,7 @@ const ModuleTitle = ({ module, viewMoreIcon = <FaAngleRight />, pageContext = nu
36
36
  >
37
37
  {module.module_title && getTitle(module)}
38
38
  {module.link_label && (
39
- <Link to={module.link_value} className={styles.viewMore}>
39
+ <Link to={module.link_value} className={`${styles.viewMore} module-title-gtm`}>
40
40
  {module.link_label}
41
41
  {viewMoreIcon}
42
42
  </Link>
@@ -57,6 +57,7 @@ ModuleTitle.propTypes = {
57
57
  style: PropTypes.string,
58
58
  }),
59
59
  viewMoreIcon: PropTypes.element,
60
+ pageContext: PropTypes.shape({}),
60
61
  };
61
62
 
62
63
  export default ModuleTitle;
@@ -0,0 +1,14 @@
1
+ /* eslint-disable react/no-unescaped-entities */
2
+ import React from 'react';
3
+ import styles from './not-found.module.scss';
4
+
5
+ const NotFound = () => (
6
+ <div className={styles.wrapper}>
7
+ <div className={styles.textBlock}>
8
+ <p>Oops! We can't seem to find that page anymore.</p>
9
+ <p>While you're here though, why not check out these top South African Casinos:</p>
10
+ </div>
11
+ </div>
12
+ );
13
+
14
+ export default NotFound;
@@ -0,0 +1,16 @@
1
+ .wrapper {
2
+ display: flex;
3
+ grid-area: main;
4
+ padding: 0 2.4rem;
5
+ margin-top: 8rem;
6
+
7
+ @include min(laptop){
8
+ margin-top: 0;
9
+ }
10
+
11
+ .textBlock{
12
+ @include min(tablet){
13
+ max-width: 60%;
14
+ }
15
+ }
16
+ }
@@ -28,7 +28,7 @@ const OpenGraph = ({ page, text = 'Share: ' }) => {
28
28
  rel="noreferrer"
29
29
  href={fbURL}
30
30
  role="button"
31
- className={styles.btn}
31
+ className={`${styles.btn} open-graph-gtm`}
32
32
  onClick={(e) => share(e, 555, 602)}
33
33
  >
34
34
  <FaFacebookF />
@@ -38,7 +38,7 @@ const OpenGraph = ({ page, text = 'Share: ' }) => {
38
38
  rel="noreferrer"
39
39
  href={twitterURL}
40
40
  role="button"
41
- className={styles.btn}
41
+ className={`${styles.btn} open-graph-gtm`}
42
42
  onClick={(e) => share(e, 555, 255)}
43
43
  >
44
44
  <FaTwitter />
@@ -50,9 +50,9 @@ const OpenGraph = ({ page, text = 'Share: ' }) => {
50
50
  OpenGraph.propTypes = {
51
51
  page: PropTypes.shape({
52
52
  title: PropTypes.string,
53
- path: PropTypes.string
53
+ path: PropTypes.string,
54
54
  }).isRequired,
55
- text: PropTypes.string
56
- }
55
+ text: PropTypes.string,
56
+ };
57
57
 
58
58
  export default OpenGraph;
@@ -1,9 +1,10 @@
1
1
  /* eslint-disable jsx-a11y/anchor-is-valid */
2
- import React from 'react';
2
+ import React, { useContext } from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
 
5
5
  import Button from '~atoms/button';
6
6
  import { prettyTracker, translate } from '~helpers/getters';
7
+ import { Context } from '~context/TranslationsProvider';
7
8
  import styles from './operator-cta.module.scss';
8
9
 
9
10
  export default function OperatorCta({
@@ -12,8 +13,9 @@ export default function OperatorCta({
12
13
  closedCasinoText = 'This Casino has closed',
13
14
  playText = 'Visit',
14
15
  tracker = 'main',
15
- translations = {},
16
+ gtmClass = '',
16
17
  }) {
18
+ const { translations } = useContext(Context) || {};
17
19
  const status = operator?.status;
18
20
  const isPlaceHolder = status === 'coming_soon';
19
21
  const isClosed = status === 'inactive';
@@ -23,7 +25,7 @@ export default function OperatorCta({
23
25
  <a
24
26
  title={placeholderText}
25
27
  aria-label={placeholderText}
26
- className={styles.operatorCtaPlaceholder}
28
+ className={`${styles.operatorCtaPlaceholder} ${gtmClass} operator-cta-gtm`}
27
29
  >
28
30
  {placeholderText}
29
31
  </a>
@@ -35,7 +37,7 @@ export default function OperatorCta({
35
37
  <a
36
38
  title={closedCasinoText}
37
39
  aria-label={closedCasinoText}
38
- className={styles.operatorCtaClosed}
40
+ className={`${styles.operatorCtaClosed} ${gtmClass} operator-cta-gtm`}
39
41
  >
40
42
  {closedCasinoText}
41
43
  </a>
@@ -45,7 +47,14 @@ export default function OperatorCta({
45
47
  const trackerType = tracker.toLowerCase().replace(' ', '_');
46
48
  const prettyLink = prettyTracker(operator, trackerType);
47
49
  const translateBtn = translate(translations, 'play_now', playText);
48
- return <Button to={prettyLink} btnText={translateBtn} isInternalLink={false} />;
50
+ return (
51
+ <Button
52
+ to={prettyLink}
53
+ btnText={translateBtn}
54
+ isInternalLink={false}
55
+ gtmClass={`${gtmClass} operator-cta-gtm btn-cta`}
56
+ />
57
+ );
49
58
  };
50
59
 
51
60
  return renderCta();
@@ -59,4 +68,5 @@ OperatorCta.propTypes = {
59
68
  placeholderText: PropTypes.string,
60
69
  playText: PropTypes.string,
61
70
  closedCasinoText: PropTypes.string,
71
+ gtmClass: PropTypes.string,
62
72
  };
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
2
  import { render, cleanup } from '@testing-library/react';
3
3
  import '@testing-library/jest-dom/extend-expect';
4
+ import getPageData from '~tests/factories/pages/default.factory';
4
5
 
5
6
  import OperatorCta from '.';
6
7
 
7
8
  describe('OperatorCta Component', () => {
8
- // Commented until we get the operator status data done on hercules
9
+ // Commented until we get the operator status data done on hercules
9
10
  // test('test placeholder', () => {
10
11
  // const { getByText } = render(<OperatorCta placeholderText="test" />);
11
12
  // expect(getByText('test')).toBeTruthy();
@@ -22,6 +23,16 @@ describe('OperatorCta Component', () => {
22
23
  // const { container } = render(<OperatorCta playText={'test3'} />);
23
24
  // expect(getByText('test3')).toBeTruthy();
24
25
  // });
26
+
27
+ test('test GTM class', () => {
28
+ const data = getPageData();
29
+ const { getByText } = render(
30
+ <OperatorCta playText="test3" gtmClass="operator-cta-gtm btn-cta" operator={data} />
31
+ );
32
+
33
+ expect(getByText('test3').closest('a').classList.contains('operator-cta-gtm')).toBe(true);
34
+ expect(getByText('test3').closest('a').classList.contains('btn-cta')).toBe(true);
35
+ });
25
36
  });
26
37
  afterEach(() => {
27
38
  cleanup();
@@ -1,3 +1,4 @@
1
+ /* eslint-disable arrow-body-style */
1
2
  /* eslint-disable no-nested-ternary */
2
3
  import React from 'react';
3
4
  import PropTypes from 'prop-types';
@@ -28,7 +29,12 @@ const OperatorInfoBlock = ({ page }) => {
28
29
  <p className={styles.label}>{item.field_label}</p>
29
30
  <div className={styles.value}>
30
31
  {item.field_name === 'url' ? (
31
- <a href={prettyLink} target="_blank" rel="noindex nofollow noreferrer">
32
+ <a
33
+ href={prettyLink}
34
+ target="_blank"
35
+ className="operator-info-block-gtm"
36
+ rel="noindex nofollow noreferrer"
37
+ >
32
38
  {relation[item.field_name]}
33
39
  </a>
34
40
  ) : item.field_name === 'support_types' ? (
@@ -60,6 +66,7 @@ const OperatorInfoBlock = ({ page }) => {
60
66
  };
61
67
 
62
68
  OperatorInfoBlock.propTypes = {
69
+ // eslint-disable-next-line react/no-unused-prop-types
63
70
  activeOperator: PropTypes.bool,
64
71
  page: PropTypes.shape({
65
72
  relation: PropTypes.shape({
@@ -10,7 +10,7 @@ const Operator = ({ item = {} }) => (
10
10
  <div className={styles.row}>
11
11
  <LazyImage src={imagePrettyUrl(item.relation.logo_url, null, 20)} />
12
12
  <h3>{item.title}</h3>
13
- <Button to="/#" primaryColor isInternalLink={false} />
13
+ <Button to="/#" primaryColor isInternalLink={false} gtmClass="operator-gtm btn-cta" />
14
14
  </div>
15
15
  );
16
16
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable react/no-danger */
1
2
  /* eslint-disable camelcase */
2
3
  import React from 'react';
3
4
  import PropTypes from 'prop-types';
@@ -36,11 +37,17 @@ const Spotlights = ({ module }) => {
36
37
  {items.map((item) => (
37
38
  <li key={keygen()} className={styles.spotlightItem}>
38
39
  {item.link.type === 'external' ? (
39
- <a href={item.link.value} title={item.label} target="_blank" rel="noreferrer">
40
+ <a
41
+ href={item.link.value}
42
+ className="spotlights-gtm"
43
+ title={item.label}
44
+ target="_blank"
45
+ rel="noreferrer"
46
+ >
40
47
  {content(item)}
41
48
  </a>
42
49
  ) : (
43
- <Link to={item.link.value} title={item.label}>
50
+ <Link to={item.link.value} title={item.label} className="spotlights-gtm">
44
51
  {content(item)}
45
52
  </Link>
46
53
  )}
@@ -54,7 +61,7 @@ const Spotlights = ({ module }) => {
54
61
  title={item.label}
55
62
  target="_blank"
56
63
  rel="noreferrer"
57
- className={styles.readMore}
64
+ className={`${styles.readMore} spotlights-gtm`}
58
65
  >
59
66
  {item.link_text ? item.link_text : 'Read More'}
60
67
  <GrFormNextLink />
@@ -62,7 +69,11 @@ const Spotlights = ({ module }) => {
62
69
  ) : (
63
70
  <>
64
71
  {item.link.value && (
65
- <Link to={item.link.value} title={item.label} className={styles.readMore}>
72
+ <Link
73
+ to={item.link.value}
74
+ title={item.label}
75
+ className={`${styles.readMore} spotlights-gtm`}
76
+ >
66
77
  {item.link_text ? item.link_text : 'Read More'}
67
78
  <GrFormNextLink />
68
79
  </Link>
@@ -1,3 +1,5 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ /* eslint-disable arrow-body-style */
1
3
  import React from 'react';
2
4
  import PropTypes from 'prop-types';
3
5
 
@@ -30,6 +32,7 @@ const Slide = ({
30
32
  btnText={primaryBtnText}
31
33
  isInternalLink={false}
32
34
  primaryColor
35
+ gtmClass="carousel-gtm btn-cta"
33
36
  />
34
37
  )}
35
38
  {item.secondary_action && (
@@ -39,6 +42,7 @@ const Slide = ({
39
42
  btnText={secondaryBtnText}
40
43
  isInternalLink={false}
41
44
  primaryColor={false}
45
+ gtmClass="carousel-gtm btn-cta"
42
46
  />
43
47
  )}
44
48
  {item.label && <span className={styles.label}>{item.label}</span>}
@@ -1,3 +1,5 @@
1
+ /* eslint-disable react/no-danger */
2
+ /* eslint-disable arrow-body-style */
1
3
  import React from 'react';
2
4
  import PropTypes from 'prop-types';
3
5
 
@@ -5,8 +7,6 @@ import CounterItem from './counter-item';
5
7
  import styles from './counter.module.scss';
6
8
  import keygen from '~helpers/keygen';
7
9
 
8
- /* eslint-disable react/no-danger */
9
-
10
10
  const Counter = ({ module }) => {
11
11
  return (
12
12
  <>
@@ -24,7 +24,10 @@ const Footer = ({
24
24
  <div className={styles.topPart}>
25
25
  <div className={styles.links}>
26
26
  {footerMenu && showLinks && (
27
- <LinkList lists={getExtraField(section.extra_fields, footerMenu)} />
27
+ <LinkList
28
+ lists={getExtraField(section.extra_fields, footerMenu)}
29
+ gtmClass="mobile-menu-gtm"
30
+ />
28
31
  )}
29
32
  </div>
30
33
 
@@ -34,7 +37,7 @@ const Footer = ({
34
37
  <div className={styles.bottomPart}>
35
38
  {footerBottomCustom && <BottomSection section={section} />}
36
39
  <div className={styles.copyrightDisclaimer}>
37
- {copyrightDisclaimer && getExtraField(section.extra_fields, copyrightDisclaimer) &&(
40
+ {copyrightDisclaimer && getExtraField(section.extra_fields, copyrightDisclaimer) && (
38
41
  <p
39
42
  dangerouslySetInnerHTML={{
40
43
  __html: getExtraField(section.extra_fields, copyrightDisclaimer).replace(
@@ -53,6 +56,7 @@ const Footer = ({
53
56
  imageOnly
54
57
  singleList
55
58
  lists={getExtraField(section.extra_fields, footerLogos)}
59
+ gtmClass="mobile-menu-gtm logo-cta"
56
60
  />
57
61
  )}
58
62
  </div>
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { render, cleanup } from '@testing-library/react';
3
3
  import '@testing-library/jest-dom/extend-expect';
4
-
5
4
  import getHeaderSection from '~tests/factories/sections/header.factory';
6
5
  import '~tests/helpers/match-media.mock';
7
6
  import Header from '.';
@@ -21,6 +21,7 @@ const LinkList = ({
21
21
  once = false,
22
22
  height,
23
23
  width,
24
+ gtmClass = '',
24
25
  }) => {
25
26
  function renderLinkContent(item, index) {
26
27
  const icon = listIcon[index];
@@ -64,11 +65,17 @@ const LinkList = ({
64
65
  title={item.title}
65
66
  rel={`noreferrer ${item.nofollow && 'nofollow'}`}
66
67
  target="_blank"
68
+ className={gtmClass}
67
69
  >
68
70
  {renderLinkContent(item, index)}
69
71
  </a>
70
72
  ) : (
71
- <Link to={item.value} title={item.title} rel={item.nofollow && 'nofollow'}>
73
+ <Link
74
+ to={item.value}
75
+ title={item.title}
76
+ className={gtmClass}
77
+ rel={item.nofollow && 'nofollow'}
78
+ >
72
79
  {renderLinkContent(item, index)}
73
80
  </Link>
74
81
  )
@@ -126,6 +133,7 @@ LinkList.propTypes = {
126
133
  once: PropTypes.bool,
127
134
  width: PropTypes.number,
128
135
  height: PropTypes.number,
136
+ gtmClass: PropTypes.string,
129
137
  };
130
138
 
131
139
  export default LinkList;
@@ -8,14 +8,16 @@ import keygen from '~helpers/keygen';
8
8
  const Main = ({ section = {}, page = {}, pageContext = {} }) => {
9
9
  const SearchPage = page.path === 's' ? loadable(() => import(`~pages/search`)) : null;
10
10
  const AuthorBox = page.author ? loadable(() => import(`~atoms/author-box`)) : null;
11
+ const NotFound = page?.path?.includes('404') ? loadable(() => import(`~atoms/not-found`)) : null;
11
12
 
12
13
  return (
13
14
  <main className={styles.modulePage}>
15
+ {NotFound && <NotFound />}
14
16
  {section.modules &&
15
17
  section.modules.map((module) => (
16
18
  <Module key={keygen()} module={module} page={page} pageContext={pageContext} />
17
19
  ))}
18
- {AuthorBox && <AuthorBox author={page.author} translations={page.translations} />}
20
+ {AuthorBox && <AuthorBox author={page.author} />}
19
21
  {SearchPage && <SearchPage page={page} />}
20
22
  </main>
21
23
  );
@@ -1,3 +1,4 @@
1
+ /* eslint-disable arrow-body-style */
1
2
  import React, { useContext, useRef } from 'react';
2
3
  import PropTypes from 'prop-types';
3
4
 
@@ -25,6 +26,7 @@ const Menu = ({
25
26
  orientation: 'horizontal',
26
27
  },
27
28
  },
29
+ gtmClass = '',
28
30
  }) => {
29
31
  let menuObject;
30
32
 
@@ -59,13 +61,14 @@ const Menu = ({
59
61
 
60
62
  return (
61
63
  <div className={styles.menuContainer}>
62
- <MenuIcon onClick={handleMenuIconClick} />
64
+ <MenuIcon onClick={handleMenuIconClick} gtmClass="main-menu-gtm" />
63
65
  <ul ref={menuListRef} className={`${menuListClasses} ${showMenu && styles.show}`}>
64
66
  {menuObject &&
65
67
  menuObject.children.map((child) => {
66
68
  return (
67
69
  <Items
68
70
  menuListRef={menuListRef}
71
+ gtmClass={gtmClass}
69
72
  key={keygen()}
70
73
  item={child}
71
74
  options={{
@@ -109,6 +112,7 @@ Menu.propTypes = {
109
112
  ),
110
113
  }).isRequired,
111
114
  menu: PropTypes.string.isRequired,
115
+ gtmClass: PropTypes.string,
112
116
  };
113
117
 
114
118
  export default Menu;
@@ -1,9 +1,8 @@
1
1
  import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
- import { prettyTracker } from '~helpers/getters';
4
+ import { prettyTracker, imagePrettyUrl } from '~helpers/getters';
5
5
  import LazyImage from '~hooks/lazy-image';
6
- import { imagePrettyUrl } from '~helpers/getters';
7
6
  import Bonus from '~atoms/bonus';
8
7
  import StarRating from '~molecules/star-rating';
9
8
  import OperatorCta from '~atoms/operator-cta';
@@ -28,7 +27,6 @@ export default function OperatorBanner({
28
27
  const clickHandler = () => {
29
28
  setShow(false);
30
29
  };
31
-
32
30
 
33
31
  return (
34
32
  show && (
@@ -45,7 +43,7 @@ export default function OperatorBanner({
45
43
  {logo ? (
46
44
  <a
47
45
  href={prettyLink}
48
- className={styles.logo}
46
+ className={`${styles.logo} operator-banner-gtm logo-cta`}
49
47
  title={operator?.name}
50
48
  target="_blank"
51
49
  rel="noreferrer"
@@ -55,7 +53,13 @@ export default function OperatorBanner({
55
53
  ) : (
56
54
  <div>
57
55
  <h3>
58
- <a href={prettyLink} title={operator?.name} target="_blank" rel="noreferrer">
56
+ <a
57
+ href={prettyLink}
58
+ title={operator?.name}
59
+ className="operator-banner-gtm name-cta"
60
+ target="_blank"
61
+ rel="noreferrer"
62
+ >
59
63
  {operator?.name}
60
64
  </a>
61
65
  </h3>
@@ -63,7 +67,13 @@ export default function OperatorBanner({
63
67
  <StarRating numOfStars={5} rating={operator.rating} />
64
68
  )}
65
69
  {isPlaceholder && hasLink && (
66
- <a href={operator.url} title={operator?.name} target="_blank" rel="noreferrer">
70
+ <a
71
+ href={operator.url}
72
+ title={operator?.name}
73
+ className="operator-banner-gtm"
74
+ target="_blank"
75
+ rel="noreferrer"
76
+ >
67
77
  {operator?.url?.replace(/^(?:https?:\/\/)?(?:www\.)?/i, '')}
68
78
  </a>
69
79
  )}
@@ -86,7 +96,7 @@ export default function OperatorBanner({
86
96
  </div>
87
97
  {sticky && (
88
98
  <button
89
- className={styles.closeBtn}
99
+ className={`${styles.closeBtn} operator-banner-gtm btn-cta`}
90
100
  onClick={clickHandler}
91
101
  aria-label="close"
92
102
  type="button"
@@ -17,7 +17,7 @@ describe('OperatorBanner Component', () => {
17
17
  expect(getByText('Visit')).toBeTruthy();
18
18
  });
19
19
  test('render component placeholder', () => {
20
- let data = getPageData();
20
+ const data = getPageData();
21
21
  data.status = 'coming_soon';
22
22
  const { container, getByText } = render(<OperatorBanner hasLink operator={data} />);
23
23
  expect(container).toBeTruthy();