gatsby-core-theme 1.6.19 → 2.0.0
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.
- package/CHANGELOG.md +92 -0
- package/gatsby-node.esm.js +23 -14
- package/package.json +2 -2
- package/src/components/app.js +4 -0
- package/src/components/atoms/iframe/index.js +15 -9
- package/src/components/atoms/menu/items/item/index.js +9 -1
- package/src/components/atoms/selling-points/index.js +1 -2
- package/src/components/atoms/selling-points/selling-points.module.scss +12 -5
- package/src/components/atoms/selling-points/selling-points.test.js +1 -1
- package/src/components/molecules/content/index.js +5 -1
- package/src/components/molecules/footer/footer.test.js +22 -22
- package/src/components/molecules/footer/index.js +3 -1
- package/src/components/molecules/header/index.js +7 -2
- package/src/components/molecules/link-list/index.js +9 -12
- package/src/components/molecules/menu/index.js +6 -1
- package/src/components/molecules/operator-banner/operator-banner.test.js +0 -1
- package/src/components/molecules/search/index.js +5 -3
- package/src/components/molecules/slider/index.js +6 -2
- package/src/components/molecules/slider/slider.test.js +30 -23
- package/src/components/molecules/star-rating/index.js +8 -24
- package/src/components/molecules/star-rating/star-rating.module.scss +13 -1
- package/src/components/molecules/star-rating/star-rating.test.js +4 -2
- package/src/components/molecules/tnc/index.js +2 -3
- package/src/components/molecules/tnc/tnc.test.js +0 -1
- package/src/components/molecules/toplist/default-row/index.js +22 -20
- package/src/components/organisms/navigation/index.js +9 -1
- package/src/components/pages/search/index.js +3 -2
- package/src/helpers/device-detect.js +5 -6
- package/src/helpers/events.js +91 -0
- package/src/helpers/generators.js +11 -3
- package/src/helpers/generators.test.js +34 -12
- package/src/helpers/processor/sports.js +0 -2
- package/src/helpers/rating.js +2 -0
- package/src/helpers/schedule.js +0 -36
- package/src/hooks/lazy-image/index.js +30 -44
- package/src/hooks/tabs/index.js +4 -2
- package/src/hooks/tabs/tabs.test.js +32 -15
- package/src/styles/utils/_mixins.scss +42 -0
- package/src/styles/utils/variables/_main.scss +8 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, cleanup, fireEvent, act } from '@testing-library/react';
|
|
2
|
+
import { render, cleanup, fireEvent, act, waitFor } from '@testing-library/react';
|
|
3
3
|
import '@testing-library/jest-dom/extend-expect';
|
|
4
4
|
import keygen from '~helpers/keygen';
|
|
5
5
|
import Slider from '.';
|
|
@@ -12,9 +12,9 @@ describe('Slider Component', () => {
|
|
|
12
12
|
act(() => {
|
|
13
13
|
const { container } = render(
|
|
14
14
|
<Slider useArrows={false} usePagination={false} settings={{ numberOfSlides: 0 }}>
|
|
15
|
-
{list.map((element) =>
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
{list.map((element) => (
|
|
16
|
+
<div key={keygen()}>{element}</div>
|
|
17
|
+
))}
|
|
18
18
|
</Slider>
|
|
19
19
|
);
|
|
20
20
|
|
|
@@ -30,9 +30,9 @@ describe('Slider Component', () => {
|
|
|
30
30
|
const list = ['Summer', 'Autumn', 'Winter', 'Spring'];
|
|
31
31
|
const { container } = render(
|
|
32
32
|
<Slider useArrows={false} usePagination={false} settings={{ numberOfSlides: 0 }}>
|
|
33
|
-
{list.map((element) =>
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
{list.map((element) => (
|
|
34
|
+
<div key={keygen()}>{element}</div>
|
|
35
|
+
))}
|
|
36
36
|
</Slider>
|
|
37
37
|
);
|
|
38
38
|
|
|
@@ -51,20 +51,24 @@ describe('Slider Component', () => {
|
|
|
51
51
|
const list = ['Summer', 'Autumn', 'Winter', 'Spring'];
|
|
52
52
|
const { container } = render(
|
|
53
53
|
<Slider>
|
|
54
|
-
{list.map((element) =>
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
{list.map((element) => (
|
|
55
|
+
<div key={keygen()}>{element}</div>
|
|
56
|
+
))}
|
|
57
57
|
</Slider>
|
|
58
58
|
);
|
|
59
59
|
|
|
60
60
|
const prev = container.querySelector('button.left');
|
|
61
61
|
const next = container.querySelector('button.right');
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
await waitFor(() => {
|
|
64
|
+
const dots = container.querySelector('div.pagination');
|
|
65
|
+
expect(dots).toBeTruthy();
|
|
66
|
+
});
|
|
67
|
+
|
|
63
68
|
const content = container.querySelector('div.sliderContent');
|
|
64
69
|
|
|
65
70
|
expect(prev).toBeTruthy();
|
|
66
71
|
expect(next).toBeTruthy();
|
|
67
|
-
expect(dots).toBeTruthy();
|
|
68
72
|
expect(content).toBeTruthy();
|
|
69
73
|
expect(content.querySelector('.active>div').innerHTML).toBe('Summer');
|
|
70
74
|
});
|
|
@@ -74,15 +78,15 @@ describe('Slider Component', () => {
|
|
|
74
78
|
|
|
75
79
|
const { container } = render(
|
|
76
80
|
<Slider>
|
|
77
|
-
{list.map((element) =>
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
{list.map((element) => (
|
|
82
|
+
<div key={keygen()}>{element}</div>
|
|
83
|
+
))}
|
|
80
84
|
</Slider>
|
|
81
85
|
);
|
|
82
86
|
|
|
83
87
|
const prev = container.querySelector('button.left');
|
|
84
88
|
const next = container.querySelector('button.right');
|
|
85
|
-
|
|
89
|
+
|
|
86
90
|
const content = container.querySelector('div.sliderContent');
|
|
87
91
|
|
|
88
92
|
fireEvent.click(next);
|
|
@@ -91,10 +95,13 @@ describe('Slider Component', () => {
|
|
|
91
95
|
fireEvent.click(prev);
|
|
92
96
|
expect(content.querySelector('.active>div').innerHTML).toBe('Summer');
|
|
93
97
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
const dots = container.querySelector('div.pagination');
|
|
100
|
+
const dot = dots.querySelectorAll('button');
|
|
101
|
+
expect(dot.length).toEqual(4);
|
|
102
|
+
fireEvent.click(dot[1]);
|
|
103
|
+
expect(content.querySelector('.active>div').innerHTML).toBe('Autumn');
|
|
104
|
+
});
|
|
98
105
|
});
|
|
99
106
|
|
|
100
107
|
test('Swipe Slides', async () => {
|
|
@@ -102,9 +109,9 @@ describe('Slider Component', () => {
|
|
|
102
109
|
act(() => {
|
|
103
110
|
const { container } = render(
|
|
104
111
|
<Slider>
|
|
105
|
-
{list.map((element) =>
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
{list.map((element) => (
|
|
113
|
+
<div key={keygen()}>{element}</div>
|
|
114
|
+
))}
|
|
108
115
|
</Slider>
|
|
109
116
|
);
|
|
110
117
|
|
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { FaStar, FaStarHalfAlt, FaRegStar } from 'react-icons/fa';
|
|
3
2
|
import PropTypes from 'prop-types';
|
|
4
|
-
import LazyLoad from 'react-lazyload';
|
|
5
3
|
|
|
6
4
|
import styles from './star-rating.module.scss';
|
|
7
5
|
import keygen from '~helpers/keygen';
|
|
8
6
|
import { getRating } from '~helpers/rating';
|
|
9
7
|
|
|
10
|
-
const StarRating = ({
|
|
11
|
-
numOfStars,
|
|
12
|
-
iconEmpty = <FaRegStar />,
|
|
13
|
-
iconHalf = <FaStarHalfAlt />,
|
|
14
|
-
iconFull = <FaStar />,
|
|
15
|
-
rating,
|
|
16
|
-
halfStars = true,
|
|
17
|
-
}) => {
|
|
8
|
+
const StarRating = ({ numOfStars, rating, halfStars = true }) => {
|
|
18
9
|
const renderFarm = () => {
|
|
19
10
|
const output = [];
|
|
20
11
|
const rate = getRating(rating);
|
|
@@ -22,38 +13,31 @@ const StarRating = ({
|
|
|
22
13
|
for (let i = 1; i < numOfStars + 1; i += 1) {
|
|
23
14
|
if (i <= rate) {
|
|
24
15
|
output.push(
|
|
25
|
-
<span className={
|
|
26
|
-
{
|
|
16
|
+
<span className={styles.fullStar} key={keygen()}>
|
|
17
|
+
{' '}
|
|
27
18
|
</span>
|
|
28
19
|
);
|
|
29
20
|
} else if (halfStars && i - 0.5 === rate) {
|
|
30
21
|
output.push(
|
|
31
|
-
<span className={
|
|
32
|
-
{
|
|
22
|
+
<span className={styles.halfStar} key={keygen()}>
|
|
23
|
+
{' '}
|
|
33
24
|
</span>
|
|
34
25
|
);
|
|
35
26
|
} else {
|
|
36
27
|
output.push(
|
|
37
|
-
<span className={
|
|
38
|
-
{
|
|
28
|
+
<span className={styles.emptyStar} key={keygen()}>
|
|
29
|
+
{' '}
|
|
39
30
|
</span>
|
|
40
31
|
);
|
|
41
32
|
}
|
|
42
33
|
}
|
|
43
34
|
return output;
|
|
44
35
|
};
|
|
45
|
-
return (
|
|
46
|
-
<LazyLoad once>
|
|
47
|
-
<div className={styles.starRatingContainer}>{renderFarm()}</div>
|
|
48
|
-
</LazyLoad>
|
|
49
|
-
);
|
|
36
|
+
return <div className={styles.starRatingContainer}>{renderFarm()}</div>;
|
|
50
37
|
};
|
|
51
38
|
|
|
52
39
|
StarRating.propTypes = {
|
|
53
40
|
numOfStars: PropTypes.oneOf([5, 10]).isRequired,
|
|
54
|
-
iconEmpty: PropTypes.element,
|
|
55
|
-
iconHalf: PropTypes.element,
|
|
56
|
-
iconFull: PropTypes.element,
|
|
57
41
|
rating: PropTypes.oneOfType([PropTypes.array, PropTypes.number, PropTypes.string]).isRequired,
|
|
58
42
|
halfStars: PropTypes.bool,
|
|
59
43
|
};
|
|
@@ -7,4 +7,16 @@
|
|
|
7
7
|
fill: var(--star-rating-color);
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
.fullStar{
|
|
12
|
+
@include star(var(--full-star-fill-color), var(--full-star-border-color))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.halfStar{
|
|
16
|
+
@include half-star(var(--half-star-border-color), var(--halfFull-star-fill-color), var(--halfEmpty-star-fill-color))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.emptyStar{
|
|
20
|
+
@include star(var(--empty-star-border-color), var(--empty-star-fill-color))
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -7,8 +7,10 @@ import StarRating from '.';
|
|
|
7
7
|
describe('StarRating Component', () => {
|
|
8
8
|
test('render container with lazyload', () => {
|
|
9
9
|
const { container } = render(<StarRating numOfStars={10} rating={6.5} />);
|
|
10
|
-
|
|
11
|
-
expect(container.querySelectorAll('.
|
|
10
|
+
|
|
11
|
+
expect(container.querySelectorAll('.fullStar')).toHaveLength(6);
|
|
12
|
+
expect(container.querySelectorAll('.halfStar')).toHaveLength(1);
|
|
13
|
+
expect(container.querySelectorAll('.emptyStar')).toHaveLength(3);
|
|
12
14
|
});
|
|
13
15
|
});
|
|
14
16
|
afterEach(() => {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import LazyLoad from 'react-lazyload';
|
|
4
3
|
|
|
5
4
|
import Collapse from '~atoms/collapse';
|
|
6
5
|
|
|
@@ -13,7 +12,7 @@ const Tnc = ({
|
|
|
13
12
|
initOpen = false,
|
|
14
13
|
operator,
|
|
15
14
|
}) => (
|
|
16
|
-
|
|
15
|
+
<>
|
|
17
16
|
{hasCollapse ? (
|
|
18
17
|
<Collapse
|
|
19
18
|
onlyMobile={onlyMobile}
|
|
@@ -26,7 +25,7 @@ const Tnc = ({
|
|
|
26
25
|
) : (
|
|
27
26
|
contentText
|
|
28
27
|
)}
|
|
29
|
-
|
|
28
|
+
</>
|
|
30
29
|
);
|
|
31
30
|
|
|
32
31
|
Tnc.propTypes = {
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { MdCheck } from 'react-icons/md';
|
|
4
|
-
|
|
5
|
-
import Button from '~atoms/button';
|
|
6
4
|
import Bonus from '~atoms/bonus';
|
|
5
|
+
import { Context } from '~context/TranslationsProvider';
|
|
7
6
|
import SellingPoints from '~atoms/selling-points';
|
|
8
|
-
|
|
9
|
-
import
|
|
7
|
+
import StarRating from '~molecules/star-rating';
|
|
8
|
+
import Link from '~hooks/link';
|
|
9
|
+
import OperatorCta from '~atoms/operator-cta';
|
|
10
|
+
import { prettyTracker, imagePrettyUrl, translate } from '~helpers/getters';
|
|
10
11
|
import LazyImage from '~hooks/lazy-image';
|
|
11
12
|
|
|
12
13
|
import styles from './default-row.module.scss';
|
|
13
14
|
|
|
14
|
-
const Row = ({ item, oneliner = 'main', layout = 'list' }) => {
|
|
15
|
+
const Row = ({ item, oneliner = 'main', layout = 'list', tracker = 'main' }) => {
|
|
15
16
|
const prettyLink = prettyTracker(item);
|
|
17
|
+
const itemRating = item.rating;
|
|
18
|
+
const { translations } = useContext(Context) || {};
|
|
16
19
|
|
|
17
20
|
return (
|
|
18
21
|
<div className={`${styles.row} ${styles[layout]}`}>
|
|
@@ -33,26 +36,23 @@ const Row = ({ item, oneliner = 'main', layout = 'list' }) => {
|
|
|
33
36
|
rel="noreferrer"
|
|
34
37
|
aria-label={`${item.name} Link`}
|
|
35
38
|
>
|
|
36
|
-
<LazyImage
|
|
39
|
+
<LazyImage
|
|
40
|
+
alt={item.name}
|
|
41
|
+
src={imagePrettyUrl(item.logo_url, 100)}
|
|
42
|
+
width={150}
|
|
43
|
+
height={40}
|
|
44
|
+
/>
|
|
37
45
|
</a>
|
|
38
46
|
<Bonus item={item} tracker={oneliner} />
|
|
47
|
+
<StarRating numOfStars={5} rating={itemRating} />
|
|
39
48
|
<SellingPoints icon={<MdCheck />} sellingPoints={item.selling_points} />
|
|
40
49
|
<div>
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
gtmClass="casinos-top-list-gtm btn-cta"
|
|
45
|
-
btnText="Omtale"
|
|
46
|
-
/>
|
|
50
|
+
<Link className={`${styles.reviewLink} toplist-variant-one-gtm`} to={item.review_link}>
|
|
51
|
+
{`${translate(translations, 'read_review', 'Review')}`}
|
|
52
|
+
</Link>
|
|
47
53
|
</div>
|
|
48
54
|
<div>
|
|
49
|
-
<
|
|
50
|
-
to={prettyLink}
|
|
51
|
-
btnText="Spill nå!"
|
|
52
|
-
gtmClass="casinos-top-list-gtm btn-cta"
|
|
53
|
-
primaryColor
|
|
54
|
-
isInternalLink={false}
|
|
55
|
-
/>
|
|
55
|
+
<OperatorCta operator={item} tracker={tracker} gtmClass="toplist-operator-cta-gtm" />
|
|
56
56
|
</div>
|
|
57
57
|
</div>
|
|
58
58
|
);
|
|
@@ -61,11 +61,13 @@ const Row = ({ item, oneliner = 'main', layout = 'list' }) => {
|
|
|
61
61
|
Row.propTypes = {
|
|
62
62
|
oneliner: PropTypes.string,
|
|
63
63
|
layout: PropTypes.string,
|
|
64
|
+
tracker: PropTypes.string,
|
|
64
65
|
item: PropTypes.shape({
|
|
65
66
|
name: PropTypes.string,
|
|
66
67
|
logo_url: PropTypes.string,
|
|
67
68
|
selling_points: PropTypes.arrayOf(PropTypes.string),
|
|
68
69
|
review_link: PropTypes.string,
|
|
70
|
+
rating: PropTypes.string,
|
|
69
71
|
one_liners: PropTypes.shape({
|
|
70
72
|
main: PropTypes.shape({
|
|
71
73
|
one_liner: PropTypes.string,
|
|
@@ -33,6 +33,7 @@ const Navigation = ({
|
|
|
33
33
|
},
|
|
34
34
|
sticky = true,
|
|
35
35
|
template,
|
|
36
|
+
customStyles,
|
|
36
37
|
}) => {
|
|
37
38
|
const navRef = useRef(React.createRef());
|
|
38
39
|
const showMenu = template !== 'ppc';
|
|
@@ -72,7 +73,13 @@ const Navigation = ({
|
|
|
72
73
|
</Link>
|
|
73
74
|
{showMenu && (
|
|
74
75
|
<>
|
|
75
|
-
<Menu
|
|
76
|
+
<Menu
|
|
77
|
+
section={section}
|
|
78
|
+
menu={menu}
|
|
79
|
+
options={options}
|
|
80
|
+
customStyles={customStyles}
|
|
81
|
+
gtmClass="main-menu-gtm"
|
|
82
|
+
/>
|
|
76
83
|
{hasSearch && <Search className={styles.search} searchIcon={searchIcon} />}
|
|
77
84
|
</>
|
|
78
85
|
)}
|
|
@@ -116,6 +123,7 @@ Navigation.propTypes = {
|
|
|
116
123
|
}),
|
|
117
124
|
}),
|
|
118
125
|
sticky: PropTypes.bool,
|
|
126
|
+
customStyles: PropTypes.string,
|
|
119
127
|
};
|
|
120
128
|
|
|
121
129
|
export default Navigation;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/* eslint-disable arrow-body-style */
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
|
-
|
|
5
|
-
import Search from '~molecules/search';
|
|
4
|
+
import loadable from '@loadable/component';
|
|
6
5
|
import Card from '~atoms/cards/default-card';
|
|
7
6
|
import { translate } from '~helpers/getters';
|
|
8
7
|
|
|
9
8
|
const SearchContent = ({ page }) => {
|
|
9
|
+
const Search = loadable(() => import('~molecules/search'));
|
|
10
|
+
|
|
10
11
|
return (
|
|
11
12
|
<Search
|
|
12
13
|
pageSearchOptions={{
|
|
@@ -14,12 +14,11 @@ export function isMobileDevice() {
|
|
|
14
14
|
const isIos = () => Boolean(userAgent.match(/iPhone|iPad|iPod/i));
|
|
15
15
|
const isOpera = () => Boolean(userAgent.match(/Opera Mini/i));
|
|
16
16
|
const isWindows = () => Boolean(userAgent.match(/IEMobile/i));
|
|
17
|
-
const isIos13 = () =>
|
|
18
|
-
Boolean(
|
|
19
|
-
platform === 'MacIntel' &&
|
|
20
|
-
maxTouchPoints &&
|
|
21
|
-
maxTouchPoints === 5
|
|
22
|
-
);
|
|
17
|
+
const isIos13 = () => Boolean(platform === 'MacIntel' && maxTouchPoints && maxTouchPoints === 5);
|
|
23
18
|
|
|
24
19
|
return Boolean(isAndroid() || isIos() || isOpera() || isWindows() || isIos13());
|
|
25
20
|
}
|
|
21
|
+
|
|
22
|
+
export function isNativeImageLazyLoadingSupported() {
|
|
23
|
+
return typeof HTMLImageElement !== 'undefined' && 'loading' in HTMLImageElement.prototype;
|
|
24
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
/* eslint-disable import/prefer-default-export */
|
|
3
|
+
import { zeroPadding } from './schedule';
|
|
4
|
+
|
|
5
|
+
function isValidDate(d) {
|
|
6
|
+
return d instanceof Date && !Number.isNaN(d);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function convertTimeZone(event) {
|
|
10
|
+
if (!event || !event.date || !event.date.time) {
|
|
11
|
+
return event;
|
|
12
|
+
}
|
|
13
|
+
const timeArr = event.date.time.split(':');
|
|
14
|
+
|
|
15
|
+
// ecmascript has month ranges between 0 - 11, that's why we do -1 to month_number
|
|
16
|
+
const currentTimeZoneDate = new Date(
|
|
17
|
+
Date.UTC(
|
|
18
|
+
event.date.year_number,
|
|
19
|
+
zeroPadding(event.date.month_number - 1, 2),
|
|
20
|
+
zeroPadding(event.date.day_number, 2),
|
|
21
|
+
timeArr[0],
|
|
22
|
+
timeArr[1]
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (!isValidDate(currentTimeZoneDate)) return event;
|
|
27
|
+
|
|
28
|
+
const time = `${zeroPadding(currentTimeZoneDate.getHours(), 2)}:${zeroPadding(
|
|
29
|
+
currentTimeZoneDate.getMinutes(),
|
|
30
|
+
2
|
|
31
|
+
)}`;
|
|
32
|
+
|
|
33
|
+
// in case the utc is 23:00, but user's timezone can get 00:00 so update the date object.
|
|
34
|
+
const day_number = zeroPadding(currentTimeZoneDate.getDate(), 2);
|
|
35
|
+
const month_number = zeroPadding(currentTimeZoneDate.getMonth() + 1, 2);
|
|
36
|
+
const date = `${day_number}-${month_number}-${zeroPadding(currentTimeZoneDate.getFullYear(), 2)}`;
|
|
37
|
+
|
|
38
|
+
const dateAttrs = {
|
|
39
|
+
date: {
|
|
40
|
+
...event.date,
|
|
41
|
+
time,
|
|
42
|
+
month_number,
|
|
43
|
+
day_number,
|
|
44
|
+
date,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return { ...event, ...dateAttrs };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function updateAllTimezones(relation) {
|
|
52
|
+
const relationSchedule = relation?.schedule;
|
|
53
|
+
const relationFeaturedEvents = relation?.featured_events;
|
|
54
|
+
const relationShowcasedEvents = relation?.showcased_events;
|
|
55
|
+
|
|
56
|
+
// formated timezone schedule
|
|
57
|
+
const schedule = relationSchedule
|
|
58
|
+
? Object.keys(relationSchedule).reduce((acc, dateKey) => {
|
|
59
|
+
const { tournaments } = relationSchedule[dateKey] || {};
|
|
60
|
+
|
|
61
|
+
const formattedTournaments = Object.keys(tournaments).reduce(
|
|
62
|
+
(tournamentAcc, currentTournamentKey) => {
|
|
63
|
+
const league = tournaments[currentTournamentKey];
|
|
64
|
+
const formattedEvents = league.events.map((event) => convertTimeZone(event));
|
|
65
|
+
tournamentAcc[currentTournamentKey] = { ...league, events: formattedEvents };
|
|
66
|
+
return tournamentAcc;
|
|
67
|
+
},
|
|
68
|
+
{}
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
acc[dateKey] = { ...relation.schedule[dateKey], tournaments: formattedTournaments };
|
|
72
|
+
return acc;
|
|
73
|
+
}, {})
|
|
74
|
+
: {};
|
|
75
|
+
|
|
76
|
+
// formated timezone featured events
|
|
77
|
+
const featured_events = relationFeaturedEvents?.map((event) => convertTimeZone(event)) || [];
|
|
78
|
+
|
|
79
|
+
// formated timezone showcased events
|
|
80
|
+
const showcased_events = relationShowcasedEvents?.map((event) => convertTimeZone(event)) || [];
|
|
81
|
+
|
|
82
|
+
// format timezone for relation.event
|
|
83
|
+
const event = convertTimeZone(relation?.event);
|
|
84
|
+
|
|
85
|
+
const updatedObject = { ...relation, schedule, featured_events, showcased_events };
|
|
86
|
+
if (event) {
|
|
87
|
+
updatedObject.event = event;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return updatedObject;
|
|
91
|
+
}
|
|
@@ -21,17 +21,25 @@ export function generateTrackerLink(operator, trackerType) {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function
|
|
24
|
+
export function generateMetaString(metaString, translations, props) {
|
|
25
25
|
const date = new Date();
|
|
26
|
+
const day = date.getDate();
|
|
26
27
|
const month = months[date.getMonth()];
|
|
27
28
|
const year = date.getFullYear();
|
|
29
|
+
const regex =
|
|
30
|
+
/\[MONTH\]|\[YEAR\]|\[currentyear\]|\[sitename\]|\[currentmonth\]|\[title\]|\[currentdate\]/gi;
|
|
28
31
|
|
|
29
|
-
return
|
|
30
|
-
|
|
32
|
+
return metaString.replace(
|
|
33
|
+
regex,
|
|
31
34
|
(match) =>
|
|
32
35
|
({
|
|
33
36
|
'[MONTH]': (translations && translations[month]) || month,
|
|
34
37
|
'[YEAR]': year,
|
|
38
|
+
'[currentdate]': `${(translations && translations[month]) || month} ${day}, ${year}`,
|
|
39
|
+
'[currentmonth]': (translations && translations[month]) || month,
|
|
40
|
+
'[currentyear]': year,
|
|
41
|
+
'[sitename]': (props && props.siteName) || '',
|
|
42
|
+
'[title]': (props && props.siteTitle) || '',
|
|
35
43
|
}[match])
|
|
36
44
|
);
|
|
37
45
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { generateTrackerLink,
|
|
1
|
+
import { generateTrackerLink, generateMetaString } from './generators';
|
|
2
2
|
import { months } from '~constants/common';
|
|
3
3
|
|
|
4
4
|
describe('Generate Tracker Link Helper', () => {
|
|
@@ -17,24 +17,46 @@ describe('Generate Tracker Link Helper', () => {
|
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
describe('Generate Meta Title Helper', () => {
|
|
20
|
-
test('
|
|
21
|
-
const
|
|
20
|
+
test('generateMetaString uppercase', () => {
|
|
21
|
+
const metaString = generateMetaString('meta title [MONTH] [YEAR]');
|
|
22
22
|
const date = new Date();
|
|
23
|
-
|
|
24
|
-
expect(
|
|
25
|
-
expect(
|
|
26
|
-
expect(
|
|
23
|
+
|
|
24
|
+
expect(metaString).not.toContain('[MONTH]');
|
|
25
|
+
expect(metaString).not.toContain('[YEAR]');
|
|
26
|
+
expect(metaString).toContain(date.getFullYear());
|
|
27
|
+
expect(metaString).toContain(months[date.getMonth()]);
|
|
28
|
+
});
|
|
29
|
+
test('generateMetaString lowercase', () => {
|
|
30
|
+
const metaString = generateMetaString(
|
|
31
|
+
'meta title [currentdate] [currentmonth] [currentyear] [sitename] [title]',
|
|
32
|
+
null,
|
|
33
|
+
{
|
|
34
|
+
siteName: 'Site Name',
|
|
35
|
+
siteTitle: 'Site Title',
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
const date = new Date();
|
|
39
|
+
|
|
40
|
+
expect(metaString).not.toContain('[currentdate]');
|
|
41
|
+
expect(metaString).not.toContain('[currentmonth]');
|
|
42
|
+
expect(metaString).not.toContain('[currentyear]');
|
|
43
|
+
expect(metaString).not.toContain('[sitename]');
|
|
44
|
+
expect(metaString).not.toContain('[title]');
|
|
45
|
+
expect(metaString).toContain(date.getDate());
|
|
46
|
+
expect(metaString).toContain(months[date.getMonth()]);
|
|
47
|
+
expect(metaString).toContain(date.getFullYear());
|
|
48
|
+
expect(metaString).toContain('Site Name');
|
|
49
|
+
expect(metaString).toContain('Site Title');
|
|
27
50
|
});
|
|
28
|
-
test('
|
|
51
|
+
test('generateMetaString translated', () => {
|
|
29
52
|
const translateMonths = months.reduce(
|
|
30
53
|
(translated, month) => ({ ...translated, [month]: `translate${month.substring(0, 1)}` }),
|
|
31
54
|
{}
|
|
32
55
|
);
|
|
33
|
-
const
|
|
56
|
+
const metaString = generateMetaString('meta title [MONTH]', translateMonths);
|
|
34
57
|
const date = new Date();
|
|
35
58
|
|
|
36
|
-
expect(
|
|
37
|
-
expect(
|
|
38
|
-
expect(metaTitle).toContain(translateMonths[months[date.getMonth()]]);
|
|
59
|
+
expect(metaString).not.toContain('[MONTH]');
|
|
60
|
+
expect(metaString).toContain(translateMonths[months[date.getMonth()]]);
|
|
39
61
|
});
|
|
40
62
|
});
|
|
@@ -6,11 +6,9 @@ import {
|
|
|
6
6
|
filterEvents,
|
|
7
7
|
findTournaments,
|
|
8
8
|
getSortedEvents,
|
|
9
|
-
formatEvents,
|
|
10
9
|
} from '../schedule';
|
|
11
10
|
|
|
12
11
|
export function prepareSportsData(sportsData) {
|
|
13
|
-
sportsData.events = formatEvents(sportsData.events);
|
|
14
12
|
Object.keys(sportsData.tournaments).forEach((key) => {
|
|
15
13
|
if (sportsData.tournaments[key].events) {
|
|
16
14
|
sportsData.tournaments[key].events = filterEvents(
|
package/src/helpers/rating.js
CHANGED
package/src/helpers/schedule.js
CHANGED
|
@@ -120,39 +120,3 @@ export function filterEvents(tournamentEvents, events) {
|
|
|
120
120
|
|
|
121
121
|
return futureEvents;
|
|
122
122
|
}
|
|
123
|
-
|
|
124
|
-
export function changeEventHour(event, hour = 1) {
|
|
125
|
-
if (!event || !event.date || !event.date.time) {
|
|
126
|
-
return event;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const timeArr = event.date.time.split(':');
|
|
130
|
-
timeArr[0] = Number(timeArr[0]) - hour;
|
|
131
|
-
event.date.time = timeArr.join(':');
|
|
132
|
-
|
|
133
|
-
return event;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function formatEvents(events) {
|
|
137
|
-
const eventsArr = Object.values(events);
|
|
138
|
-
const siteName = process.env.GATSBY_SITE_NAME;
|
|
139
|
-
let prefix = '0';
|
|
140
|
-
|
|
141
|
-
switch (siteName) {
|
|
142
|
-
case 'sefodbold.dk':
|
|
143
|
-
case 'sesport.dk':
|
|
144
|
-
case 'watchfooty.co.uk':
|
|
145
|
-
case 'bekijksport.nl':
|
|
146
|
-
case 'livestreamsvoetbal.nl':
|
|
147
|
-
prefix = 1;
|
|
148
|
-
break;
|
|
149
|
-
default:
|
|
150
|
-
prefix = 0;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return eventsArr.reduce((acc, current) => {
|
|
154
|
-
const event = changeEventHour(current, prefix);
|
|
155
|
-
acc[event.id] = event;
|
|
156
|
-
return acc;
|
|
157
|
-
}, {});
|
|
158
|
-
}
|