gatsby-core-theme 1.6.22 → 2.0.3
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 +85 -0
- package/gatsby-node.esm.js +14 -3
- package/package.json +1 -1
- package/src/components/app.js +4 -0
- package/src/components/atoms/iframe/index.js +15 -9
- 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 +10 -1
- package/src/components/molecules/link-list/index.js +9 -12
- package/src/components/molecules/operator-banner/operator-banner.test.js +0 -1
- package/src/components/molecules/star-rating/index.js +10 -22
- package/src/components/molecules/star-rating/star-rating.module.scss +13 -1
- package/src/components/molecules/star-rating/star-rating.test.js +5 -4
- 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/helpers/device-detect.js +5 -6
- package/src/helpers/events.js +102 -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
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,88 @@
|
|
|
1
|
+
## [2.0.3](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v2.0.2...v2.0.3) (2021-12-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* fixed schedule for rage ppc ([02f910f](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/02f910f01b3ac1e9b442a1dc0a3e8f19466bac23))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Code Refactoring
|
|
10
|
+
|
|
11
|
+
* remove unneeded check ([2201e4d](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/2201e4d14c17684a4f49e2035af99ace83b108b1))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
* Merge branch 'fix-build-schedule' into 'master' ([356b451](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/356b451459a126c41a6f27e0b0fcfbd300d45679))
|
|
15
|
+
|
|
16
|
+
## [2.0.2](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v2.0.1...v2.0.2) (2021-12-17)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* added lazyload for starrating ([34a3bce](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/34a3bce70bde1e9364f4c5aba14845d19d39664e))
|
|
22
|
+
* content iframe lazy ([413f83d](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/413f83d70eb05aa514f003e450afce04366537d5))
|
|
23
|
+
* tests ([c56a1c0](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/c56a1c0168247d25f8445f6b9ed8102c6bae8c08))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
* Merge branch 'master' of git.ilcd.rocks:team-floyd/themes/gatsby-themes ([4c1f4f3](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/4c1f4f3c5f366cd57245ca2ef9bb5ec603d13e97))
|
|
27
|
+
|
|
28
|
+
## [2.0.1](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v2.0.0...v2.0.1) (2021-12-16)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### Bug Fixes
|
|
32
|
+
|
|
33
|
+
* link list bug ([893b8c1](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/893b8c12737a4007c94364ace744e7c1d7459706))
|
|
34
|
+
|
|
35
|
+
# [2.0.0](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v1.6.22...v2.0.0) (2021-12-16)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Bug Fixes
|
|
39
|
+
|
|
40
|
+
* add function to transform event datetime ([7167a6b](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/7167a6b52e0a19064f2a906fe30a4cccfeca41e4))
|
|
41
|
+
* added full date format in currentdate placeholder ([275d9d3](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/275d9d3b9b2394acfe8074e50ada241c86aee133))
|
|
42
|
+
* added lazyload if native lazy is not supported ([d27115c](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/d27115cca38920a11fdca342d3eb631490ee0108))
|
|
43
|
+
* added translation in toplist default row ([c4c100e](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/c4c100eb9e1b5ce67e72bb42551cbb37311969f7))
|
|
44
|
+
* content fix ([73a6eac](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/73a6eac2cbc4c1bb428312b95867e844c2c2abcd))
|
|
45
|
+
* content module removed parser and used replace function ([cc2973f](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/cc2973f42e6db2fcd999879e97af502092d65324))
|
|
46
|
+
* lazyimage component ([5230b91](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/5230b91bbde26015ebaf49621d8c47207b20d3c6))
|
|
47
|
+
* removed direct mutating, and wip on replacing all events with updated timezone ([1571eb8](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/1571eb86149eedc74c9a69c77102ceb10d16c9aa))
|
|
48
|
+
* removed function that changes root scss variables ([0b60602](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/0b60602002774f3c9d3b2895f87574e3c6c75d44))
|
|
49
|
+
* removed unused lazyloads ([9cc1c5c](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/9cc1c5c4a89d3e67fe65d85c2e57dd6854dd76a4))
|
|
50
|
+
* replace star svg with css ([868e3a2](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/868e3a20ce2804c3deab67d62f64348e657bdbf1))
|
|
51
|
+
* return main component as it was ([db3aca5](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/db3aca55c82839d0d281b77b7225a6f75d35c1d7))
|
|
52
|
+
* selling points icon color moved to css var ([7283fc1](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/7283fc1ef56a7fae24acca91f65a72c0752cd635))
|
|
53
|
+
* selling points tick ([71b3aaf](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/71b3aaf4105c6584ede11791cac14a04f8fe9338))
|
|
54
|
+
* small fix ([f6444c1](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/f6444c1f7421dd9063e9029d02eb8441ec10ffc3))
|
|
55
|
+
* small issue ([43be83b](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/43be83bdd5fa5b3d5fe13160a78432a9963c33ec))
|
|
56
|
+
* small issue ([1d49e35](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/1d49e357d2098c557d0f7b16e6ab9d7033f16674))
|
|
57
|
+
* test fixed issue ([320e030](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/320e030e49a8c6d7e461578d01e72c2948bdec5a))
|
|
58
|
+
* tests and lazy iframe ([c0b63d5](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/c0b63d5445f85f7e6b5539b628f516ecbc86547d))
|
|
59
|
+
* tests and lazy iframe ([364f449](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/364f449965ee3998b2dbbdb5132c6a91951ff000))
|
|
60
|
+
* toplist row images ([3ffeb17](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/3ffeb17696e2d82fe8b9841defe2b6e78be1e68b))
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
### Code Refactoring
|
|
64
|
+
|
|
65
|
+
* add error handling for invalid date ([caa308b](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/caa308b9b50352228d86d031c449918c7d81840a))
|
|
66
|
+
* remove unneeded function ([d2fb77a](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/d2fb77a3810e5b767b716d87db4fb63853995d46))
|
|
67
|
+
* tabs set to loadable ([9079a60](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/9079a60aaead65be9d70629fdd1025ce46ed8db8))
|
|
68
|
+
* translations change on operator cta ([0a476cf](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/0a476cf2f1ab02eeba06db8af9eaf692b9715b75))
|
|
69
|
+
* translations change on operator cta ([ee9fded](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/ee9fded3227ab34287d539676bc581bcb1a5abee))
|
|
70
|
+
* update placeholders generation for meta tags ([0a4e14b](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/0a4e14bf2f594a7c28b5698df06436df43bd378c))
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
### Config
|
|
74
|
+
|
|
75
|
+
* merged master ([08e4355](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/08e43557f6f3827f612fed9448d0db5a5d65577a))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
* Merge branch 'add_timezone_prefix' into 'master' ([b5d22b5](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/b5d22b57eb52d8ed97e2928706c98d437a08738b))
|
|
79
|
+
* Merge branch 'tm-2617-update-placeholders-for-meta-tags' into 'master' ([9c5bf49](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/9c5bf492688ddb28d01182a5f46ce18d8f7342d6))
|
|
80
|
+
* Merge branch 'cta-play-now' into 'master' ([29107c4](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/29107c4da0339cb798b4c6b5c9dfe98c69bab015))
|
|
81
|
+
* Merge branch 'master' into cta-play-now ([f6aa117](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/f6aa11733e67c700aa44fd8dec7b918c8d3db661))
|
|
82
|
+
* Merge branch 'selling-points' into 'master' ([4dc0e96](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/4dc0e96e48f5219bbeede529fd346e16ede5b514))
|
|
83
|
+
* Merge branch 'star-rating' into 'master' ([ecc5e24](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/ecc5e24f9e9f45e72c1ee50dd552fb1a68d04f44))
|
|
84
|
+
* Update .env.development ([a91cd2f](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/a91cd2fc6355e31644d22749cb98ec1e2c81160a))
|
|
85
|
+
|
|
1
86
|
## [1.6.22](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v1.6.21...v1.6.22) (2021-12-10)
|
|
2
87
|
|
|
3
88
|
|
package/gatsby-node.esm.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { cloneDeep, chunk, pick } from 'lodash';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import { getData, getLocalData } from './src/helpers/api';
|
|
8
|
-
import {
|
|
8
|
+
import { generateMetaString, generateTrackerLink } from './src/helpers/generators';
|
|
9
9
|
import processor, { processSitemapPages } from './src/helpers/processor';
|
|
10
10
|
import { pickAuthorsPageKeys } from './src/constants/pick-keys';
|
|
11
11
|
|
|
@@ -211,8 +211,19 @@ exports.createPages = async ({ actions: { createPage } }, themeOptions) => {
|
|
|
211
211
|
page.authors = Object.keys(authors || {}).map((key) =>
|
|
212
212
|
pick(authors[key], pickAuthorsPageKeys)
|
|
213
213
|
);
|
|
214
|
-
// Done for matrix-theme sites for
|
|
215
|
-
page.meta_title =
|
|
214
|
+
// Done for matrix-theme sites for placeholders auto update
|
|
215
|
+
page.meta_title =
|
|
216
|
+
page.meta_title &&
|
|
217
|
+
generateMetaString(page.meta_title, translations, {
|
|
218
|
+
siteName: response.general.site_name,
|
|
219
|
+
siteTitle: page.title,
|
|
220
|
+
});
|
|
221
|
+
page.meta_description =
|
|
222
|
+
page.meta_description &&
|
|
223
|
+
generateMetaString(page.meta_description, translations, {
|
|
224
|
+
siteName: response.general.site_name,
|
|
225
|
+
siteTitle: page.title,
|
|
226
|
+
});
|
|
216
227
|
|
|
217
228
|
const contextData = {
|
|
218
229
|
page,
|
package/package.json
CHANGED
package/src/components/app.js
CHANGED
|
@@ -66,6 +66,10 @@ const App = ({ pageContext }) => {
|
|
|
66
66
|
|
|
67
67
|
const TrackerContent = isTracker ? loadable(() => import(`~pages/tracker`)) : null;
|
|
68
68
|
|
|
69
|
+
if (pageContext.siteInfo?.site_name === 'playcasino.co.za') {
|
|
70
|
+
translations.play_now = 'Play now';
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
return isTracker ? (
|
|
70
74
|
<>
|
|
71
75
|
<Head page={pageContext.page} siteInfo={pageContext.siteInfo} />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import loadable from '@loadable/component';
|
|
4
|
+
import { isNativeImageLazyLoadingSupported } from '~helpers/device-detect';
|
|
5
5
|
import styles from './iframe.module.scss';
|
|
6
6
|
|
|
7
7
|
const Iframe = ({
|
|
@@ -10,9 +10,10 @@ const Iframe = ({
|
|
|
10
10
|
minHeight = '45rem',
|
|
11
11
|
lazyLoad = true,
|
|
12
12
|
frameBorder = 1,
|
|
13
|
-
}) =>
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
}) => {
|
|
14
|
+
if (!isNativeImageLazyLoadingSupported() && lazyLoad) {
|
|
15
|
+
const LazyLoad = loadable(() => import(`react-lazyload`));
|
|
16
|
+
return (
|
|
16
17
|
<LazyLoad>
|
|
17
18
|
<iframe
|
|
18
19
|
title={title}
|
|
@@ -21,16 +22,21 @@ const Iframe = ({
|
|
|
21
22
|
frameBorder={frameBorder}
|
|
22
23
|
/>
|
|
23
24
|
</LazyLoad>
|
|
24
|
-
)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className={styles.iframeContainer}>
|
|
25
30
|
<iframe
|
|
26
31
|
title={title}
|
|
27
32
|
style={{ width: '100%', minHeight, display: 'block' }}
|
|
28
33
|
src={src}
|
|
34
|
+
loading={lazyLoad ? 'lazy' : 'eager'}
|
|
29
35
|
frameBorder={frameBorder}
|
|
30
36
|
/>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
34
40
|
|
|
35
41
|
Iframe.propTypes = {
|
|
36
42
|
src: PropTypes.string.isRequired,
|
|
@@ -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 keygen from '~helpers/keygen';
|
|
6
5
|
import styles from './selling-points.module.scss';
|
|
@@ -13,7 +12,7 @@ const SellingPoints = ({ sellingPoints, icon, limit = 3 }) => {
|
|
|
13
12
|
<ul className={styles.sellingPoint}>
|
|
14
13
|
{sellingPoints.slice(0, limit).map((item) => (
|
|
15
14
|
<li key={keygen()}>
|
|
16
|
-
{icon &&
|
|
15
|
+
<span className={`${icon && styles.tick}`}>{` `}</span>
|
|
17
16
|
<span>{item}</span>
|
|
18
17
|
</li>
|
|
19
18
|
))}
|
|
@@ -7,11 +7,18 @@
|
|
|
7
7
|
font-size: 1.4rem;
|
|
8
8
|
width: 100%;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
.tick {
|
|
11
|
+
position: relative;
|
|
12
|
+
margin-left: 2rem;
|
|
13
|
+
&::before {
|
|
14
|
+
@include arrow(var(--selling-point-icon-color), 1.5rem, down, false);
|
|
15
|
+
position: absolute;
|
|
16
|
+
padding: 0px 0px .8rem .32rem;
|
|
17
|
+
border-right-width: .18rem;
|
|
18
|
+
border-bottom-width: .18rem;
|
|
19
|
+
bottom: -.3rem;
|
|
20
|
+
left: -1.8rem;
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
}
|
|
17
24
|
|
|
@@ -24,7 +24,7 @@ describe('Selling Points Component', () => {
|
|
|
24
24
|
const { container } = render(
|
|
25
25
|
<SellingPoints sellingPoints={sellingPointsList} icon={<p>test icon</p>} />
|
|
26
26
|
);
|
|
27
|
-
expect(container.querySelectorAll('.
|
|
27
|
+
expect(container.querySelectorAll('.tick')).toHaveLength(3);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test('test empty selling point list', () => {
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
+
/* eslint-disable react/forbid-prop-types */
|
|
2
|
+
/* eslint-disable react/no-danger */
|
|
1
3
|
import React from 'react';
|
|
2
|
-
import parse from 'html-react-parser';
|
|
3
4
|
import PropTypes from 'prop-types';
|
|
5
|
+
import parse from 'html-react-parser';
|
|
4
6
|
|
|
7
|
+
import loadable from '@loadable/component';
|
|
5
8
|
import LazyImage from '~hooks/lazy-image';
|
|
6
9
|
import { parseCss } from '~helpers/css-parser';
|
|
7
10
|
import styles from './content.module.scss';
|
|
8
11
|
|
|
9
12
|
const Content = ({ module, pageContext = null }) => {
|
|
10
13
|
const replaceMedia = (node) => {
|
|
14
|
+
if (node.name === 'iframe') {
|
|
15
|
+
const Iframe = loadable(() => import('gatsby-core-theme/src/components/atoms/iframe'));
|
|
16
|
+
return <Iframe src={node.attribs.src} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
if (node.name === 'img') {
|
|
12
20
|
let stylesClass = null;
|
|
13
21
|
const classes = node.attribs.class;
|
|
@@ -49,6 +57,7 @@ const Content = ({ module, pageContext = null }) => {
|
|
|
49
57
|
};
|
|
50
58
|
|
|
51
59
|
Content.propTypes = {
|
|
60
|
+
pageContext: PropTypes.object,
|
|
52
61
|
module: PropTypes.shape({
|
|
53
62
|
anchor_label: PropTypes.string,
|
|
54
63
|
name: PropTypes.string,
|
|
@@ -26,18 +26,15 @@ const LinkList = ({
|
|
|
26
26
|
function renderLinkContent(item, index) {
|
|
27
27
|
const icon = listIcon[index];
|
|
28
28
|
|
|
29
|
-
const LinkImage = () =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/>
|
|
39
|
-
);
|
|
40
|
-
};
|
|
29
|
+
const LinkImage = () => (
|
|
30
|
+
<LazyImage
|
|
31
|
+
src={imagePrettyUrl(item.image)}
|
|
32
|
+
alt={item.title}
|
|
33
|
+
width={width}
|
|
34
|
+
height={height}
|
|
35
|
+
loading={disableLazyLoad ? 'eager' : 'lazy'}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
41
38
|
|
|
42
39
|
return (
|
|
43
40
|
<>
|
|
@@ -12,7 +12,6 @@ describe('OperatorBanner Component', () => {
|
|
|
12
12
|
);
|
|
13
13
|
expect(container).toBeTruthy();
|
|
14
14
|
expect(container.querySelectorAll('.sticky')).toHaveLength(1);
|
|
15
|
-
expect(container.querySelectorAll('.lazyload-placeholder')).toHaveLength(1);
|
|
16
15
|
expect(getByText('Rizk Casino')).toBeTruthy();
|
|
17
16
|
expect(getByText('Visit')).toBeTruthy();
|
|
18
17
|
});
|
|
@@ -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
3
|
import LazyLoad from 'react-lazyload';
|
|
5
|
-
|
|
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,20 +13,20 @@ 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
|
}
|
|
@@ -43,17 +34,14 @@ const StarRating = ({
|
|
|
43
34
|
return output;
|
|
44
35
|
};
|
|
45
36
|
return (
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
</
|
|
37
|
+
<div className={styles.starRatingContainer}>
|
|
38
|
+
<LazyLoad>{renderFarm()}</LazyLoad>
|
|
39
|
+
</div>
|
|
49
40
|
);
|
|
50
41
|
};
|
|
51
42
|
|
|
52
43
|
StarRating.propTypes = {
|
|
53
44
|
numOfStars: PropTypes.oneOf([5, 10]).isRequired,
|
|
54
|
-
iconEmpty: PropTypes.element,
|
|
55
|
-
iconHalf: PropTypes.element,
|
|
56
|
-
iconFull: PropTypes.element,
|
|
57
45
|
rating: PropTypes.oneOfType([PropTypes.array, PropTypes.number, PropTypes.string]).isRequired,
|
|
58
46
|
halfStars: PropTypes.bool,
|
|
59
47
|
};
|
|
@@ -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
|
+
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, cleanup } from '@testing-library/react';
|
|
2
|
+
import { render, cleanup, waitFor } from '@testing-library/react';
|
|
3
3
|
import '@testing-library/jest-dom/extend-expect';
|
|
4
4
|
|
|
5
5
|
import StarRating from '.';
|
|
6
6
|
|
|
7
7
|
describe('StarRating Component', () => {
|
|
8
|
-
test('render container with lazyload', () => {
|
|
8
|
+
test('render container with lazyload', async () => {
|
|
9
9
|
const { container } = render(<StarRating numOfStars={10} rating={6.5} />);
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
await waitFor(() => {
|
|
11
|
+
expect(container.querySelectorAll('.lazyload-placeholder')).toHaveLength(1);
|
|
12
|
+
});
|
|
12
13
|
});
|
|
13
14
|
});
|
|
14
15
|
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,
|
|
@@ -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,102 @@
|
|
|
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
|
+
function updateSchedule(schedule) {
|
|
52
|
+
if (!schedule) {
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Object.keys(schedule).reduce((acc, key) => {
|
|
57
|
+
const { tournaments } = schedule[key] || {};
|
|
58
|
+
if (!tournaments && ['soccer', 'handball', 'tennis', 'cricket'].includes(key)) {
|
|
59
|
+
const value = updateSchedule(schedule[key]);
|
|
60
|
+
acc[key] = value;
|
|
61
|
+
return acc;
|
|
62
|
+
}
|
|
63
|
+
// else if schedule is normal format
|
|
64
|
+
const formattedTournaments = Object.keys(tournaments).reduce(
|
|
65
|
+
(tournamentAcc, currentTournamentKey) => {
|
|
66
|
+
const league = tournaments[currentTournamentKey];
|
|
67
|
+
const formattedEvents = league.events.map((event) => convertTimeZone(event));
|
|
68
|
+
|
|
69
|
+
tournamentAcc[currentTournamentKey] = { ...league, events: formattedEvents };
|
|
70
|
+
return tournamentAcc;
|
|
71
|
+
},
|
|
72
|
+
{}
|
|
73
|
+
);
|
|
74
|
+
acc[key] = { ...schedule[key], tournaments: formattedTournaments };
|
|
75
|
+
return acc;
|
|
76
|
+
}, {});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function updateAllTimezones(relation) {
|
|
80
|
+
const relationSchedule = relation?.schedule;
|
|
81
|
+
const relationFeaturedEvents = relation?.featured_events;
|
|
82
|
+
const relationShowcasedEvents = relation?.showcased_events;
|
|
83
|
+
|
|
84
|
+
// formated timezone schedule
|
|
85
|
+
const schedule = updateSchedule(relationSchedule);
|
|
86
|
+
|
|
87
|
+
// formated timezone featured events
|
|
88
|
+
const featured_events = relationFeaturedEvents?.map((event) => convertTimeZone(event)) || [];
|
|
89
|
+
|
|
90
|
+
// formated timezone showcased events
|
|
91
|
+
const showcased_events = relationShowcasedEvents?.map((event) => convertTimeZone(event)) || [];
|
|
92
|
+
|
|
93
|
+
// format timezone for relation.event
|
|
94
|
+
const event = convertTimeZone(relation?.event);
|
|
95
|
+
|
|
96
|
+
const updatedObject = { ...relation, schedule, featured_events, showcased_events };
|
|
97
|
+
if (event) {
|
|
98
|
+
updatedObject.event = event;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return updatedObject;
|
|
102
|
+
}
|
|
@@ -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
|
-
}
|
|
@@ -1,39 +1,29 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
|
-
// import LazyLoad from 'react-lazyload';
|
|
4
3
|
import PropTypes from 'prop-types';
|
|
4
|
+
import loadable from '@loadable/component';
|
|
5
|
+
import { isNativeImageLazyLoadingSupported } from '~helpers/device-detect';
|
|
5
6
|
|
|
6
|
-
// When to use this component:
|
|
7
|
-
// 1. If you have 1 image to lazyload
|
|
8
|
-
// 2. If you have images for different breakpoints and want the browser to decide when to serve the images based on the device, bandwidth, etc.
|
|
9
7
|
export default function LazyImage({
|
|
10
8
|
height,
|
|
11
9
|
width,
|
|
12
|
-
// offset = 200,
|
|
13
10
|
style = {},
|
|
14
11
|
className,
|
|
15
12
|
src = '#',
|
|
16
|
-
// srcSet = '',
|
|
17
13
|
alt = '',
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// once = false,
|
|
14
|
+
defaultImg,
|
|
15
|
+
loading = 'lazy',
|
|
21
16
|
}) {
|
|
22
|
-
|
|
17
|
+
const [errorImage, setErrorImage] = useState(false);
|
|
23
18
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
if ((defaultImg && !src) || errorImage === true) {
|
|
20
|
+
return defaultImg;
|
|
21
|
+
}
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
width={`${width}px`}
|
|
33
|
-
offset={offset}
|
|
34
|
-
debounce={0}
|
|
35
|
-
once={once}
|
|
36
|
-
>
|
|
23
|
+
if (!isNativeImageLazyLoadingSupported()) {
|
|
24
|
+
const LazyLoad = loadable(() => import(`react-lazyload`));
|
|
25
|
+
return (
|
|
26
|
+
<LazyLoad height={`${height}px`} width={`${width}px`} debounce={0}>
|
|
37
27
|
<img
|
|
38
28
|
src={src}
|
|
39
29
|
className={className}
|
|
@@ -41,36 +31,32 @@ export default function LazyImage({
|
|
|
41
31
|
width={width}
|
|
42
32
|
alt={alt}
|
|
43
33
|
style={style}
|
|
44
|
-
srcSet={srcSet}
|
|
45
|
-
sizes={sizes}
|
|
46
|
-
onError={() => setErrorImage(true)}
|
|
47
34
|
/>
|
|
48
|
-
</LazyLoad>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
{
|
|
60
|
-
|
|
35
|
+
</LazyLoad>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<img
|
|
41
|
+
src={src}
|
|
42
|
+
loading={loading}
|
|
43
|
+
className={className}
|
|
44
|
+
height={height}
|
|
45
|
+
width={width}
|
|
46
|
+
alt={alt}
|
|
47
|
+
style={style}
|
|
48
|
+
onError={() => setErrorImage(true)}
|
|
49
|
+
/>
|
|
61
50
|
);
|
|
62
51
|
}
|
|
63
52
|
|
|
64
53
|
LazyImage.propTypes = {
|
|
65
54
|
width: PropTypes.number,
|
|
66
55
|
height: PropTypes.number,
|
|
67
|
-
// offset: PropTypes.number,
|
|
68
56
|
style: PropTypes.shape({}),
|
|
69
57
|
className: PropTypes.string,
|
|
70
58
|
src: PropTypes.string,
|
|
71
59
|
alt: PropTypes.string,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// defaultImg: PropTypes.element,
|
|
75
|
-
// once: PropTypes.bool,
|
|
60
|
+
defaultImg: PropTypes.element,
|
|
61
|
+
loading: PropTypes.string,
|
|
76
62
|
};
|
package/src/hooks/tabs/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { forceCheck } from 'react-lazyload';
|
|
4
|
-
import
|
|
4
|
+
import loadable from '@loadable/component';
|
|
5
5
|
import styles from './tabs.module.scss';
|
|
6
6
|
|
|
7
7
|
const Tabs = ({
|
|
@@ -19,6 +19,8 @@ const Tabs = ({
|
|
|
19
19
|
showAll ? showAllTabId : `${children[0].props.label}_0`
|
|
20
20
|
);
|
|
21
21
|
|
|
22
|
+
const TabList = showTabs ? loadable(() => import('./tab/tab-list')) : null;
|
|
23
|
+
|
|
22
24
|
const tabHeaderClass = `${styles.tabsHeader} ${!HeaderComp && styles.tabsOnly} ${
|
|
23
25
|
styles[headerClass]
|
|
24
26
|
} ${tabsAlign === 'right' && styles.invertOrder}`;
|
|
@@ -31,7 +33,7 @@ const Tabs = ({
|
|
|
31
33
|
return (
|
|
32
34
|
<>
|
|
33
35
|
<div className={tabHeaderClass}>
|
|
34
|
-
{
|
|
36
|
+
{TabList && (
|
|
35
37
|
<TabList
|
|
36
38
|
onClick={onClickTabItem}
|
|
37
39
|
items={children}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, cleanup, fireEvent } from '@testing-library/react';
|
|
2
|
+
import { render, cleanup, fireEvent, waitFor } from '@testing-library/react';
|
|
3
3
|
import '@testing-library/jest-dom/extend-expect';
|
|
4
4
|
|
|
5
5
|
import Tabs from '.';
|
|
6
6
|
|
|
7
7
|
describe('Tabs Component', () => {
|
|
8
|
-
test('render tabs', () => {
|
|
8
|
+
test('render tabs', async () => {
|
|
9
9
|
const { container, getByText } = render(
|
|
10
10
|
<Tabs tabsAlign="right" HeaderComp={<div className="header">my header</div>}>
|
|
11
11
|
<div label="one" key={1}>
|
|
@@ -19,15 +19,18 @@ describe('Tabs Component', () => {
|
|
|
19
19
|
</div>
|
|
20
20
|
</Tabs>
|
|
21
21
|
);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
|
|
23
|
+
await waitFor(() => {
|
|
24
|
+
expect(container.querySelectorAll('.tabListItem')).toHaveLength(2);
|
|
25
|
+
// tabsAlign="right"
|
|
26
|
+
expect(container.querySelectorAll('div.tabsHeader.invertOrder')).toHaveLength(1);
|
|
27
|
+
// // HeaderComp
|
|
28
|
+
expect(getByText('my header')).toBeTruthy();
|
|
29
|
+
expect(getByText('1111111111111')).toBeTruthy();
|
|
30
|
+
});
|
|
28
31
|
});
|
|
29
32
|
|
|
30
|
-
test('show all', () => {
|
|
33
|
+
test('show all', async () => {
|
|
31
34
|
const { container, getByText } = render(
|
|
32
35
|
<Tabs
|
|
33
36
|
tabsAlign="left"
|
|
@@ -45,12 +48,14 @@ describe('Tabs Component', () => {
|
|
|
45
48
|
</div>
|
|
46
49
|
</Tabs>
|
|
47
50
|
);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
await waitFor(() => {
|
|
52
|
+
expect(container.querySelectorAll('.tabListItem')).toHaveLength(3);
|
|
53
|
+
expect(container.querySelectorAll('div.tabsHeader')).toHaveLength(1);
|
|
54
|
+
expect(getByText('1111111111111222222233333333')).toBeInTheDocument();
|
|
55
|
+
});
|
|
51
56
|
});
|
|
52
57
|
|
|
53
|
-
test('switch tabs', () => {
|
|
58
|
+
test('switch tabs', async () => {
|
|
54
59
|
const { getByText } = render(
|
|
55
60
|
<Tabs tabsAlign="right" HeaderComp={<div className="header">my header</div>}>
|
|
56
61
|
<div label="one" key={1}>
|
|
@@ -64,11 +69,23 @@ describe('Tabs Component', () => {
|
|
|
64
69
|
</div>
|
|
65
70
|
</Tabs>
|
|
66
71
|
);
|
|
72
|
+
|
|
73
|
+
await waitFor(() => {
|
|
74
|
+
expect(getByText('two')).toBeTruthy();
|
|
75
|
+
});
|
|
76
|
+
|
|
67
77
|
fireEvent.click(getByText('two'));
|
|
68
78
|
expect(getByText('2222222')).toBeTruthy();
|
|
69
|
-
|
|
79
|
+
|
|
80
|
+
await waitFor(() => {
|
|
81
|
+
fireEvent.click(getByText('three'));
|
|
82
|
+
});
|
|
83
|
+
|
|
70
84
|
expect(getByText('33333333')).toBeTruthy();
|
|
71
|
-
|
|
85
|
+
|
|
86
|
+
await waitFor(() => {
|
|
87
|
+
fireEvent.click(getByText('one'));
|
|
88
|
+
});
|
|
72
89
|
expect(getByText('1111111111111')).toBeTruthy();
|
|
73
90
|
});
|
|
74
91
|
});
|
|
@@ -84,3 +84,45 @@
|
|
|
84
84
|
background: linear-gradient(to bottom, $color2 0, $color1 100%);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
@mixin star($border-color: #fba62f, $fill-color: #fba62f) {
|
|
89
|
+
line-height: 2rem;
|
|
90
|
+
width: 16px;
|
|
91
|
+
font-weight: normal;
|
|
92
|
+
display: inline-block;
|
|
93
|
+
color: $fill-color;
|
|
94
|
+
font-size: 15px;
|
|
95
|
+
position: relative;
|
|
96
|
+
text-shadow: -1px 0 $border-color, 0 1px $border-color, 1px 0 $border-color, 0 -1px $border-color;
|
|
97
|
+
|
|
98
|
+
&:last-child {
|
|
99
|
+
margin-right: 0;
|
|
100
|
+
}
|
|
101
|
+
&:before {
|
|
102
|
+
content: '\2605';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@mixin half-star($border-color: #fba62f, $half-empty-color: #fba62f , $half-full-color: white) {
|
|
108
|
+
line-height: 2rem;
|
|
109
|
+
width: 16px;
|
|
110
|
+
font-weight: normal;
|
|
111
|
+
display: inline-block;
|
|
112
|
+
color: $half-full-color;
|
|
113
|
+
font-size: 15px;
|
|
114
|
+
position: relative;
|
|
115
|
+
&:before {
|
|
116
|
+
content: '\2605';
|
|
117
|
+
}
|
|
118
|
+
text-shadow: -1px 0 $border-color, 0 1px $border-color, 1px 0 $border-color, 0 -1px $border-color;
|
|
119
|
+
&:after {
|
|
120
|
+
content: '\2605';
|
|
121
|
+
color: $half-empty-color;
|
|
122
|
+
position: absolute;
|
|
123
|
+
width: 7px;
|
|
124
|
+
overflow: hidden;
|
|
125
|
+
bottom: 0;
|
|
126
|
+
left: 0;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -9,6 +9,13 @@
|
|
|
9
9
|
--secondary-text-color: var(--color-4);
|
|
10
10
|
--heading-base-color: var(--color-12);
|
|
11
11
|
--text-link-color: var(--color-13);
|
|
12
|
+
--full-star-fill-color: #fba62f;
|
|
13
|
+
--full-star-border-color: #fba62f;
|
|
14
|
+
--halfFull-star-fill-color: #fba62f;
|
|
15
|
+
--halfEmpty-star-fill-color: white;
|
|
16
|
+
--half-star-border-color: #fba62f;
|
|
17
|
+
--empty-star-fill-color: white;
|
|
18
|
+
--empty-star-border-color: grey;
|
|
12
19
|
|
|
13
20
|
// Font
|
|
14
21
|
--main-font: Nunito;
|
|
@@ -51,6 +58,7 @@
|
|
|
51
58
|
--modal-background-color: white;
|
|
52
59
|
|
|
53
60
|
--star-rating-color: orange;
|
|
61
|
+
--selling-point-icon-color: #00889e;
|
|
54
62
|
|
|
55
63
|
--scroll-to-top-background-color: var(--color-1);
|
|
56
64
|
|