gatsby-matrix-theme 53.25.0 → 53.26.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 +22 -0
- package/package.json +2 -2
- package/src/components/atoms/coupon/index.js +176 -39
- package/src/components/atoms/recommended-operators/index.js +14 -1
- package/src/components/molecules/wagering-calculator/index.js +4 -1
- package/storybook/public/{251.46f52818.iframe.bundle.js → 251.733af458.iframe.bundle.js} +4 -4
- package/storybook/public/{251.46f52818.iframe.bundle.js.map → 251.733af458.iframe.bundle.js.map} +1 -1
- package/storybook/public/iframe.html +1 -1
- package/storybook/public/main.17af33f6.iframe.bundle.js +1 -0
- package/storybook/public/project.json +2 -1
- package/storybook/public/main.7e1380dd.iframe.bundle.js +0 -1
- /package/storybook/public/{251.46f52818.iframe.bundle.js.LICENSE.txt → 251.733af458.iframe.bundle.js.LICENSE.txt} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
# [53.26.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/compare/v53.25.1...v53.26.0) (2026-07-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Config
|
|
5
|
+
|
|
6
|
+
* update theme ([ea2f1a2](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/commit/ea2f1a2d125636833c6cba9061949cf6bea0d4b0))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
* Merge branch 'EN-576/coupon-acts-as-cta' into 'master' ([fe0c2ad](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/commit/fe0c2adb0e51d6744e064cad5a01e689ec6865ef))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* coupon acts as CTA with tracking and delayed operator redirect ([b27d65c](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/commit/b27d65ce42b9f5650fecdbab6be312dadefa3f2d))
|
|
15
|
+
|
|
16
|
+
## [53.25.1](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/compare/v53.25.0...v53.25.1) (2026-07-07)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* update matrix version ([29b2c67](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/commit/29b2c679cdebfd9eaacbea2347e18dd268f30603))
|
|
22
|
+
|
|
1
23
|
# [53.25.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/matrix-theme/compare/v53.24.0...v53.25.0) (2026-07-02)
|
|
2
24
|
|
|
3
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gatsby-matrix-theme",
|
|
3
|
-
"version": "53.
|
|
3
|
+
"version": "53.26.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"description": "Matrix Theme NPM Package",
|
|
6
6
|
"author": "",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@react-icons/all-files": "^4.1.0",
|
|
27
27
|
"@gigmedia/enigma-utils": "^1.20.0",
|
|
28
28
|
"gatsby": "^5.11.0",
|
|
29
|
-
"gatsby-core-theme": "44.
|
|
29
|
+
"gatsby-core-theme": "44.31.0",
|
|
30
30
|
"gatsby-plugin-sharp": "^5.11.0",
|
|
31
31
|
"gatsby-plugin-sitemap": "^6.13.1",
|
|
32
32
|
"gatsby-transformer-sharp": "^5.11.0",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable react/jsx-no-target-blank */
|
|
2
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
2
3
|
import PropTypes from 'prop-types';
|
|
4
|
+
import useCtaClickHandler from 'gatsby-core-theme/src/hooks/useCtaClickHandler/index';
|
|
5
|
+
import { prettyTracker } from 'gatsby-core-theme/src/helpers/getters';
|
|
6
|
+
import { getCtaDataAttributes } from 'gatsby-core-theme/src/helpers/tracker';
|
|
3
7
|
import useTranslate from '~hooks/useTranslate/useTranslate';
|
|
4
8
|
import CopyIcon from '../../../images/icons/copy-icon';
|
|
5
9
|
import CheckCircleIcon from '../../../images/icons/check-circle';
|
|
@@ -15,26 +19,142 @@ const Coupon = ({
|
|
|
15
19
|
icon = <CopyIcon />,
|
|
16
20
|
checkIcon = <CheckCircleIcon />,
|
|
17
21
|
showIcon = true,
|
|
18
|
-
shortCode
|
|
22
|
+
shortCode,
|
|
23
|
+
// CTA / redirect behaviour (opt-in)
|
|
24
|
+
actLikeCta = false,
|
|
25
|
+
operator = null,
|
|
26
|
+
tracker = 'main',
|
|
27
|
+
moduleName = null,
|
|
28
|
+
pageTemplate = null,
|
|
29
|
+
clickedElement = 'coupon',
|
|
30
|
+
modulePosition,
|
|
31
|
+
itemPosition,
|
|
32
|
+
rel = 'nofollow sponsored',
|
|
33
|
+
redirectDelay = 2000
|
|
19
34
|
}) => {
|
|
20
|
-
if (!code) return;
|
|
21
|
-
|
|
22
35
|
const [copySuccess, setCopySuccess] = useState('');
|
|
36
|
+
const redirectTimer = useRef(null);
|
|
37
|
+
const isPending = useRef(false); // a redirect is scheduled
|
|
38
|
+
const allowNavigation = useRef(false); // the next click is our own re-dispatch
|
|
39
|
+
|
|
40
|
+
// Reuses the core CTA tracking: `fireTracking` drops the affiliate cookie /
|
|
41
|
+
// fires the pixel; `ctaRef` points at the coupon anchor we redirect through.
|
|
42
|
+
const { ctaRef, fireTracking } = useCtaClickHandler({
|
|
43
|
+
pageTemplate,
|
|
44
|
+
moduleName,
|
|
45
|
+
tracker,
|
|
46
|
+
clickedElement,
|
|
47
|
+
modulePosition,
|
|
48
|
+
itemPosition
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Clear a scheduled redirect if the component unmounts mid-flow
|
|
52
|
+
useEffect(
|
|
53
|
+
() => () => {
|
|
54
|
+
if (redirectTimer.current) clearTimeout(redirectTimer.current);
|
|
55
|
+
},
|
|
56
|
+
[]
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Resolve translations unconditionally so the hook order stays stable across
|
|
60
|
+
// the copy/redirect state change (Rules of Hooks — useTranslate uses useContext).
|
|
61
|
+
const prefixLabel = useTranslate(translationKey, defaultTranslation);
|
|
62
|
+
const noCouponLabel = useTranslate('no_coupon_available', 'Not Needed');
|
|
63
|
+
const codeCopiedLabel = useTranslate('code_copied', 'CODE COPIED');
|
|
64
|
+
|
|
65
|
+
if (!code) return null;
|
|
66
|
+
|
|
67
|
+
const inactive = status === 'inactive';
|
|
68
|
+
const isBet365 = shortCode === 'bet365';
|
|
69
|
+
|
|
70
|
+
const trackerType = tracker?.toLowerCase()?.replace(' ', '_');
|
|
71
|
+
const prettyLink = actLikeCta ? prettyTracker(operator, trackerType, false) : null;
|
|
72
|
+
// Only act as a CTA when we have a valid outbound link for an active operator
|
|
73
|
+
const ctaEnabled = actLikeCta && !!prettyLink && !inactive && !isBet365;
|
|
74
|
+
|
|
75
|
+
const handleClick = async (e) => {
|
|
76
|
+
// Our own re-dispatched click: let the anchor navigate + GTM record it
|
|
77
|
+
if (allowNavigation.current) {
|
|
78
|
+
allowNavigation.current = false;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
23
81
|
|
|
24
|
-
|
|
25
|
-
e.
|
|
26
|
-
e.stopPropagation();
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
e.stopPropagation();
|
|
27
84
|
|
|
85
|
+
if (inactive || isBet365) return;
|
|
86
|
+
// Ignore extra clicks while a redirect is already queued
|
|
87
|
+
if (isPending.current) return;
|
|
88
|
+
|
|
89
|
+
let copied = false;
|
|
28
90
|
try {
|
|
29
|
-
await navigator.clipboard.writeText(
|
|
30
|
-
|
|
91
|
+
await navigator.clipboard.writeText(code);
|
|
92
|
+
copied = true;
|
|
31
93
|
} catch (err) {
|
|
32
|
-
|
|
94
|
+
copied = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!ctaEnabled) {
|
|
98
|
+
// Original behaviour: flip the label immediately, no redirect
|
|
99
|
+
setCopySuccess(copied);
|
|
100
|
+
return;
|
|
33
101
|
}
|
|
102
|
+
|
|
103
|
+
// t=0: code is on the clipboard — flip to "copied" and drop the tracking cookie
|
|
104
|
+
setCopySuccess(true);
|
|
105
|
+
fireTracking();
|
|
106
|
+
isPending.current = true;
|
|
107
|
+
|
|
108
|
+
// t=redirectDelay: open the operator in a new tab by re-dispatching a real
|
|
109
|
+
// click on the anchor (so GTM's outbound-click trigger fires), then revert
|
|
110
|
+
// the "copied" state. The delay stays within the browser's transient-activation
|
|
111
|
+
// window so the programmatic open is not blocked as a popup.
|
|
112
|
+
redirectTimer.current = setTimeout(() => {
|
|
113
|
+
isPending.current = false;
|
|
114
|
+
|
|
115
|
+
const anchor = ctaRef.current;
|
|
116
|
+
if (!anchor) return;
|
|
117
|
+
|
|
118
|
+
// Re-dispatch a real click so the anchor navigates (new tab) and GTM's
|
|
119
|
+
// outbound-click trigger still fires. `allowNavigation` lets our own
|
|
120
|
+
// handler fall through instead of intercepting the click again.
|
|
121
|
+
allowNavigation.current = true;
|
|
122
|
+
const clickEvent = new MouseEvent('click', {
|
|
123
|
+
bubbles: true,
|
|
124
|
+
cancelable: true,
|
|
125
|
+
view: window
|
|
126
|
+
});
|
|
127
|
+
const opened = anchor.dispatchEvent(clickEvent);
|
|
128
|
+
|
|
129
|
+
// If a wrapping anchor (e.g. a parent PrettyLink) cancelled the default
|
|
130
|
+
// navigation, open the operator manually so the tab still opens.
|
|
131
|
+
if (!opened && prettyLink) {
|
|
132
|
+
window.open(prettyLink, '_blank');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Revert to the default label once the redirect has fired.
|
|
136
|
+
setCopySuccess(false);
|
|
137
|
+
}, redirectDelay);
|
|
34
138
|
};
|
|
35
139
|
|
|
36
|
-
const
|
|
37
|
-
|
|
140
|
+
const couponClass = `${styles.coupon} ${copySuccess ? styles.copied : ''}
|
|
141
|
+
${code === null ? styles.noCode : ''}
|
|
142
|
+
${inactive ? styles.disabled : ''}`;
|
|
143
|
+
|
|
144
|
+
const couponContent = !copySuccess ? (
|
|
145
|
+
<>
|
|
146
|
+
{templateOne && showprefix && (
|
|
147
|
+
<span className={styles.prefix}>{prefixLabel}</span>
|
|
148
|
+
)}
|
|
149
|
+
{code || noCouponLabel}
|
|
150
|
+
{showIcon && code !== null && !inactive && !isBet365 && icon}
|
|
151
|
+
</>
|
|
152
|
+
) : (
|
|
153
|
+
<>
|
|
154
|
+
<span>{codeCopiedLabel}</span>
|
|
155
|
+
{showIcon && checkIcon}
|
|
156
|
+
</>
|
|
157
|
+
);
|
|
38
158
|
|
|
39
159
|
return (
|
|
40
160
|
<div
|
|
@@ -43,33 +163,35 @@ const Coupon = ({
|
|
|
43
163
|
} `}
|
|
44
164
|
>
|
|
45
165
|
{!templateOne && showprefix && (
|
|
46
|
-
<span className={styles.prefix}>{
|
|
166
|
+
<span className={styles.prefix}>{prefixLabel}</span>
|
|
167
|
+
)}
|
|
168
|
+
{ctaEnabled ? (
|
|
169
|
+
<a
|
|
170
|
+
ref={ctaRef}
|
|
171
|
+
href={prettyLink}
|
|
172
|
+
target="_blank"
|
|
173
|
+
rel={rel}
|
|
174
|
+
onClick={handleClick}
|
|
175
|
+
className={couponClass}
|
|
176
|
+
{...getCtaDataAttributes(operator, {
|
|
177
|
+
tracker,
|
|
178
|
+
moduleName,
|
|
179
|
+
modulePosition,
|
|
180
|
+
itemPosition
|
|
181
|
+
})}
|
|
182
|
+
>
|
|
183
|
+
{couponContent}
|
|
184
|
+
</a>
|
|
185
|
+
) : (
|
|
186
|
+
<button
|
|
187
|
+
onClick={handleClick}
|
|
188
|
+
type="button"
|
|
189
|
+
className={couponClass}
|
|
190
|
+
disabled={inactive || isBet365}
|
|
191
|
+
>
|
|
192
|
+
{couponContent}
|
|
193
|
+
</button>
|
|
47
194
|
)}
|
|
48
|
-
<button
|
|
49
|
-
onClick={(e) => (code !== null && !inactive && !isBet365 ? copyToClipBoard(e, code) : '')}
|
|
50
|
-
type="button"
|
|
51
|
-
className={`${styles.coupon} ${copySuccess ? styles.copied : ''}
|
|
52
|
-
${code === null ? styles.noCode : ''}
|
|
53
|
-
${inactive ? styles.disabled : ''}`}
|
|
54
|
-
disabled={inactive || isBet365}
|
|
55
|
-
>
|
|
56
|
-
{!copySuccess ? (
|
|
57
|
-
<>
|
|
58
|
-
{templateOne && showprefix && (
|
|
59
|
-
<span className={styles.prefix}>
|
|
60
|
-
{useTranslate(translationKey, defaultTranslation)}
|
|
61
|
-
</span>
|
|
62
|
-
)}
|
|
63
|
-
{code || useTranslate('no_coupon_available', 'Not Needed')}
|
|
64
|
-
{showIcon && code !== null && !inactive && !isBet365 && icon}
|
|
65
|
-
</>
|
|
66
|
-
) : (
|
|
67
|
-
<>
|
|
68
|
-
<span>{useTranslate('code_copied', 'CODE COPIED')}</span>
|
|
69
|
-
{showIcon && checkIcon}
|
|
70
|
-
</>
|
|
71
|
-
)}
|
|
72
|
-
</button>
|
|
73
195
|
</div>
|
|
74
196
|
);
|
|
75
197
|
};
|
|
@@ -84,7 +206,22 @@ Coupon.propTypes = {
|
|
|
84
206
|
showIcon: PropTypes.bool,
|
|
85
207
|
translationKey: PropTypes.string,
|
|
86
208
|
defaultTranslation: PropTypes.string,
|
|
87
|
-
shortCode:PropTypes.string
|
|
209
|
+
shortCode: PropTypes.string,
|
|
210
|
+
actLikeCta: PropTypes.bool,
|
|
211
|
+
operator: PropTypes.shape({
|
|
212
|
+
name: PropTypes.string,
|
|
213
|
+
short_name: PropTypes.string,
|
|
214
|
+
status: PropTypes.string,
|
|
215
|
+
type: PropTypes.string
|
|
216
|
+
}),
|
|
217
|
+
tracker: PropTypes.string,
|
|
218
|
+
moduleName: PropTypes.string,
|
|
219
|
+
pageTemplate: PropTypes.string,
|
|
220
|
+
clickedElement: PropTypes.string,
|
|
221
|
+
modulePosition: PropTypes.number,
|
|
222
|
+
itemPosition: PropTypes.number,
|
|
223
|
+
rel: PropTypes.string,
|
|
224
|
+
redirectDelay: PropTypes.number
|
|
88
225
|
};
|
|
89
226
|
|
|
90
227
|
export default Coupon;
|
|
@@ -13,6 +13,7 @@ import styles from './recommended-operators.module.scss';
|
|
|
13
13
|
|
|
14
14
|
const RecommendedOperators = ({
|
|
15
15
|
showCouponCode = false,
|
|
16
|
+
couponActsAsCta = false,
|
|
16
17
|
showRating = false,
|
|
17
18
|
showAuthor = false,
|
|
18
19
|
title = 'Recommended Casinos:',
|
|
@@ -62,7 +63,18 @@ const RecommendedOperators = ({
|
|
|
62
63
|
</div>
|
|
63
64
|
{(showCouponCode && couponCode) && (
|
|
64
65
|
<div className={styles.couponCtaContainer}>
|
|
65
|
-
<Coupon
|
|
66
|
+
<Coupon
|
|
67
|
+
code={couponCode}
|
|
68
|
+
shortCode={operator?.short_name}
|
|
69
|
+
actLikeCta={couponActsAsCta}
|
|
70
|
+
operator={operator}
|
|
71
|
+
tracker="main"
|
|
72
|
+
clickedElement="coupon"
|
|
73
|
+
pageTemplate={pageTemplate}
|
|
74
|
+
moduleName={TrackingKeys?.WAGERINGCALCULATOR}
|
|
75
|
+
modulePosition={modulePosition}
|
|
76
|
+
itemPosition={index + 1}
|
|
77
|
+
/>
|
|
66
78
|
<OperatorCta
|
|
67
79
|
operator={operator}
|
|
68
80
|
tracker="main"
|
|
@@ -95,6 +107,7 @@ export default RecommendedOperators;
|
|
|
95
107
|
|
|
96
108
|
RecommendedOperators.propTypes = {
|
|
97
109
|
showCouponCode: PropTypes.bool,
|
|
110
|
+
couponActsAsCta: PropTypes.bool,
|
|
98
111
|
showRating: PropTypes.bool,
|
|
99
112
|
tncFixed: PropTypes.bool,
|
|
100
113
|
showAuthor: PropTypes.bool,
|
|
@@ -21,7 +21,8 @@ const WageringCalculator = ({
|
|
|
21
21
|
pageContext = {},
|
|
22
22
|
buttonType = 'primary',
|
|
23
23
|
modulePosition,
|
|
24
|
-
currency = '€'
|
|
24
|
+
currency = '€',
|
|
25
|
+
couponActsAsCta = false
|
|
25
26
|
}) => {
|
|
26
27
|
const [depositAmount, setDepositAmount] = useState('');
|
|
27
28
|
const [bonusAmount, setBonusAmount] = useState('');
|
|
@@ -180,6 +181,7 @@ const WageringCalculator = ({
|
|
|
180
181
|
operators={operators}
|
|
181
182
|
pageTemplate={pageContext?.page?.template}
|
|
182
183
|
modulePosition={modulePosition}
|
|
184
|
+
couponActsAsCta={couponActsAsCta}
|
|
183
185
|
/>
|
|
184
186
|
)}
|
|
185
187
|
</div>
|
|
@@ -198,6 +200,7 @@ WageringCalculator.propTypes = {
|
|
|
198
200
|
}),
|
|
199
201
|
modulePosition: PropTypes.number,
|
|
200
202
|
currency: PropTypes.string,
|
|
203
|
+
couponActsAsCta: PropTypes.bool,
|
|
201
204
|
};
|
|
202
205
|
|
|
203
206
|
export default WageringCalculator;
|