gatsby-core-theme 44.30.0 → 44.30.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.
- package/CHANGELOG.md +17 -0
- package/package.json +1 -1
- package/src/components/atoms/notifications/index.js +4 -1
- package/src/components/atoms/notifications/notification-items/bonuses/bonuses.test.js +8 -5
- package/src/components/atoms/notifications/notification-items/bonuses/index.js +90 -19
- package/src/components/atoms/notifications/notification-items/cards-v2/index.js +28 -20
- package/src/components/atoms/notifications/notification-items/cards-v2/notification-items.module.scss +10 -9
- package/src/components/atoms/notifications/notification-items/spotlight/index.js +32 -21
- package/src/components/atoms/notifications/notifications.module.scss +49 -0
- package/src/components/atoms/notifications/panel-header/panel-header.module.scss +2 -2
- package/src/components/atoms/notifications/panel-tabs/index.js +3 -3
- package/src/components/atoms/notifications/panel-tabs/panel-tabs.module.scss +1 -3
- package/src/helpers/date-time.js +8 -0
- package/src/helpers/date-time.test.js +8 -1
- package/src/images/icons/check-circle.js +1 -1
- package/src/resolver/modules.mjs +42 -2
- package/src/resolver/modules.test.js +40 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [44.30.2](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.30.1...v44.30.2) (2026-06-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* fixes for notification panel ([80c7649](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/80c7649bb5650317b017c336b3b9653fa52a1042))
|
|
7
|
+
|
|
8
|
+
## [44.30.1](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.30.0...v44.30.1) (2026-06-22)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* fix style of notification panel ([b21a180](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/b21a1808842776e36ef14f3f8f1fbe70a20f1854))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
* Merge branch 'master' of gitlab.com:g2m-gentoo/team-floyd/themes/gatsby-themes ([850c758](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/850c7581eb1a7a19fa20b63eace13032cd54919a))
|
|
17
|
+
|
|
1
18
|
# [44.30.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.29.0...v44.30.0) (2026-06-22)
|
|
2
19
|
|
|
3
20
|
|
package/package.json
CHANGED
|
@@ -25,7 +25,7 @@ const getNotificationToplist = (modules) => {
|
|
|
25
25
|
);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const Notifications = ({ section, market }) => {
|
|
28
|
+
const Notifications = ({ section, market, hideBadges = false }) => {
|
|
29
29
|
const { setShowSearch, setShowMenu, showMenu, showSearch } =
|
|
30
30
|
useContext(NavigationContext);
|
|
31
31
|
const notificationRef = useRef(null);
|
|
@@ -139,6 +139,7 @@ const Notifications = ({ section, market }) => {
|
|
|
139
139
|
activeTab={activeTab}
|
|
140
140
|
onTabChange={setActiveTab}
|
|
141
141
|
market={market}
|
|
142
|
+
hideBadges={hideBadges}
|
|
142
143
|
/>
|
|
143
144
|
|
|
144
145
|
<div className={styles.content}>
|
|
@@ -146,6 +147,7 @@ const Notifications = ({ section, market }) => {
|
|
|
146
147
|
<BonusesItems
|
|
147
148
|
toplist={notificationToplist}
|
|
148
149
|
showUnread={newNotification}
|
|
150
|
+
hideBadges={hideBadges}
|
|
149
151
|
/>
|
|
150
152
|
) : (
|
|
151
153
|
renderTrendingContent()
|
|
@@ -163,6 +165,7 @@ Notifications.propTypes = {
|
|
|
163
165
|
section: PropTypes.shape({
|
|
164
166
|
modules: PropTypes.arrayOf(PropTypes.shape({})),
|
|
165
167
|
}),
|
|
168
|
+
hideBadges: PropTypes.bool
|
|
166
169
|
};
|
|
167
170
|
|
|
168
171
|
export default Notifications;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
3
3
|
import '@testing-library/jest-dom/extend-expect';
|
|
4
4
|
import { getListToplistItem } from '~tests/factories/modules/toplist.factory';
|
|
5
5
|
import BonusesItems from '.';
|
|
@@ -25,7 +25,7 @@ const buildToplist = (overrides = {}) => ({
|
|
|
25
25
|
describe('BonusesItems', () => {
|
|
26
26
|
beforeEach(() => {
|
|
27
27
|
Object.assign(navigator, {
|
|
28
|
-
clipboard: { writeText: jest.fn() },
|
|
28
|
+
clipboard: { writeText: jest.fn().mockResolvedValue(undefined) },
|
|
29
29
|
});
|
|
30
30
|
});
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ describe('BonusesItems', () => {
|
|
|
34
34
|
expect(screen.getByText('No new items')).toBeVisible();
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
test('renders bonus item with promo code and copies on click', () => {
|
|
37
|
+
test('renders bonus item with promo code and copies on click', async () => {
|
|
38
38
|
const toplist = buildToplist();
|
|
39
39
|
const { container } = render(<BonusesItems toplist={toplist} showUnread />);
|
|
40
40
|
|
|
@@ -44,7 +44,10 @@ describe('BonusesItems', () => {
|
|
|
44
44
|
expect(screen.getByText('BONUS123')).toBeVisible();
|
|
45
45
|
|
|
46
46
|
fireEvent.click(screen.getByText('BONUS123'));
|
|
47
|
-
|
|
47
|
+
await waitFor(() => {
|
|
48
|
+
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('BONUS123');
|
|
49
|
+
expect(screen.getByText('CODE COPIED')).toBeVisible();
|
|
50
|
+
});
|
|
48
51
|
});
|
|
49
52
|
|
|
50
53
|
test('renders bonus item without promo code row', () => {
|
|
@@ -60,4 +63,4 @@ describe('BonusesItems', () => {
|
|
|
60
63
|
expect(container.querySelector('.bonusCodeRow')).toBeFalsy();
|
|
61
64
|
expect(screen.getByText('name1 Review')).toBeVisible();
|
|
62
65
|
});
|
|
63
|
-
});
|
|
66
|
+
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useState } from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
import { FaArrowRight } from "@react-icons/all-files/fa/FaArrowRight";
|
|
4
4
|
import CopyIcon from "~images/icons/copyIcon";
|
|
5
|
+
import CheckCircleIcon from "~images/icons/check-circle";
|
|
5
6
|
import LazyImage from "~hooks/lazy-image";
|
|
6
7
|
import PrettyLink from "~atoms/pretty-link";
|
|
7
8
|
import ReviewLink from "~atoms/review-link";
|
|
@@ -10,11 +11,13 @@ import keygen from "~helpers/keygen";
|
|
|
10
11
|
import {
|
|
11
12
|
getBonusData,
|
|
12
13
|
getPromoCode,
|
|
14
|
+
getOperatorTnc,
|
|
13
15
|
imagePrettyUrl,
|
|
14
16
|
} from "~helpers/getters";
|
|
15
17
|
import { getAltText } from "~helpers/image";
|
|
16
|
-
import { getTimeAgo } from "~helpers/date-time";
|
|
18
|
+
import { getTimeAgo, parseSortableDate } from "~helpers/date-time";
|
|
17
19
|
import { TrackingKeys } from "~constants/tracking-api";
|
|
20
|
+
import VerifiedBadgeIcon from "~images/icons/verifiedBadgeIcon";
|
|
18
21
|
import useTranslate from "~hooks/useTranslate/useTranslate";
|
|
19
22
|
import styles from "../../notifications.module.scss";
|
|
20
23
|
|
|
@@ -25,7 +28,9 @@ const BonusItem = ({
|
|
|
25
28
|
showUnread,
|
|
26
29
|
bonusCodeLabel,
|
|
27
30
|
updatedLabel,
|
|
31
|
+
hideBadges
|
|
28
32
|
}) => {
|
|
33
|
+
const [copySuccess, setCopySuccess] = useState(false);
|
|
29
34
|
const bonus = getBonusData(item, tracker);
|
|
30
35
|
const oneliner = [bonus?.mainLine, bonus?.secondLine]
|
|
31
36
|
.filter(Boolean)
|
|
@@ -34,14 +39,45 @@ const BonusItem = ({
|
|
|
34
39
|
const reviewPath = item.review_link
|
|
35
40
|
? `/${item.review_link}`
|
|
36
41
|
: item.path || null;
|
|
37
|
-
const timeData = getTimeAgo(item.updated_at)
|
|
42
|
+
const timeData = item.updated_at ? getTimeAgo(item.updated_at) : null;
|
|
38
43
|
const timeKeyLabel = useTranslate(
|
|
39
|
-
timeData
|
|
40
|
-
timeData
|
|
44
|
+
timeData?.key,
|
|
45
|
+
timeData?.key?.replace(/_/g, " ")
|
|
41
46
|
);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
const foundedYear = item?.founded?.substring(0, 4);
|
|
48
|
+
let timeAgo = "";
|
|
49
|
+
|
|
50
|
+
if (timeData?.value) {
|
|
51
|
+
timeAgo = `${updatedLabel} ${timeData.value} ${timeKeyLabel}`;
|
|
52
|
+
} else if (foundedYear) {
|
|
53
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
54
|
+
timeAgo = `${useTranslate("founded", "Founded")} ${foundedYear}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const hasTnc = Boolean(getOperatorTnc(item, tracker));
|
|
58
|
+
|
|
59
|
+
const verifiedMonth = new Intl.DateTimeFormat("en-US", {
|
|
60
|
+
month: "long",
|
|
61
|
+
}).format(new Date());
|
|
62
|
+
|
|
63
|
+
const verifiedLabel = useTranslate(
|
|
64
|
+
"notification_verified_in",
|
|
65
|
+
"Verified in [month]"
|
|
66
|
+
).replace("[month]", verifiedMonth);
|
|
67
|
+
const codeCopiedLabel = useTranslate("code_copied", "CODE COPIED");
|
|
68
|
+
const isBet365 = item.short_name === "bet365";
|
|
69
|
+
|
|
70
|
+
const copyToClipBoard = async (e, copyMe) => {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
e.stopPropagation();
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await navigator.clipboard.writeText(copyMe);
|
|
76
|
+
setCopySuccess(true);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
setCopySuccess(false);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
45
81
|
|
|
46
82
|
return (
|
|
47
83
|
<li className={styles.bonusItem}>
|
|
@@ -59,7 +95,7 @@ const BonusItem = ({
|
|
|
59
95
|
width={52}
|
|
60
96
|
height={52}
|
|
61
97
|
alt={getAltText(item.logo, item.name)}
|
|
62
|
-
src={imagePrettyUrl(item.logo?.filename
|
|
98
|
+
src={imagePrettyUrl(item.logo?.filename)}
|
|
63
99
|
/>
|
|
64
100
|
</PrettyLink>
|
|
65
101
|
|
|
@@ -70,11 +106,30 @@ const BonusItem = ({
|
|
|
70
106
|
<span className={styles.bonusCodeLabel}>{bonusCodeLabel}</span>
|
|
71
107
|
<button
|
|
72
108
|
type="button"
|
|
73
|
-
className={styles.bonusCode}
|
|
74
|
-
onClick={() =>
|
|
109
|
+
className={`${styles.bonusCode} ${copySuccess ? styles.bonusCodeCopied : ""}`}
|
|
110
|
+
onClick={(e) =>
|
|
111
|
+
promoCode && !isBet365 ? copyToClipBoard(e, promoCode) : undefined
|
|
112
|
+
}
|
|
113
|
+
disabled={isBet365}
|
|
75
114
|
>
|
|
76
|
-
|
|
77
|
-
|
|
115
|
+
{!copySuccess ? (
|
|
116
|
+
<>
|
|
117
|
+
<span>{promoCode}</span>
|
|
118
|
+
{!isBet365 && <CopyIcon width={20} height={20} />}
|
|
119
|
+
</>
|
|
120
|
+
) : (
|
|
121
|
+
<>
|
|
122
|
+
<span>{codeCopiedLabel}</span>
|
|
123
|
+
<span className={styles.bonusCodeCheckIcon}>
|
|
124
|
+
<CheckCircleIcon
|
|
125
|
+
width={20}
|
|
126
|
+
height={20}
|
|
127
|
+
bgColor="var(--notification-bonus-code-border, #20cd77)"
|
|
128
|
+
color="#fff"
|
|
129
|
+
/>
|
|
130
|
+
</span>
|
|
131
|
+
</>
|
|
132
|
+
)}
|
|
78
133
|
</button>
|
|
79
134
|
</div>
|
|
80
135
|
)}
|
|
@@ -102,10 +157,18 @@ const BonusItem = ({
|
|
|
102
157
|
)}
|
|
103
158
|
{timeAgo && <span className={styles.updated}>{timeAgo}</span>}
|
|
104
159
|
</div>
|
|
160
|
+
{hideBadges && (
|
|
161
|
+
<span className={styles.customVerifiedBadge}>
|
|
162
|
+
<VerifiedBadgeIcon />
|
|
163
|
+
{verifiedLabel}
|
|
164
|
+
</span>
|
|
165
|
+
)}
|
|
105
166
|
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
|
|
167
|
+
{hasTnc && (
|
|
168
|
+
<div className={styles.legal}>
|
|
169
|
+
<Tnc operator={item} tracker={tracker} isFixed />
|
|
170
|
+
</div>
|
|
171
|
+
)}
|
|
109
172
|
</li>
|
|
110
173
|
);
|
|
111
174
|
};
|
|
@@ -117,6 +180,7 @@ BonusItem.propTypes = {
|
|
|
117
180
|
updated_at: PropTypes.string,
|
|
118
181
|
short_name: PropTypes.string,
|
|
119
182
|
name: PropTypes.string,
|
|
183
|
+
founded: PropTypes.string,
|
|
120
184
|
logo: PropTypes.shape({
|
|
121
185
|
filename: PropTypes.string,
|
|
122
186
|
}),
|
|
@@ -126,10 +190,15 @@ BonusItem.propTypes = {
|
|
|
126
190
|
showUnread: PropTypes.bool,
|
|
127
191
|
bonusCodeLabel: PropTypes.string.isRequired,
|
|
128
192
|
updatedLabel: PropTypes.string.isRequired,
|
|
193
|
+
hideBadges: PropTypes.bool
|
|
129
194
|
};
|
|
130
195
|
|
|
131
|
-
const BonusesItems = ({ toplist, showUnread }) => {
|
|
132
|
-
const items = toplist?.items || []
|
|
196
|
+
const BonusesItems = ({ toplist, showUnread, hideBadges }) => {
|
|
197
|
+
const items = [...(toplist?.items || [])].sort(
|
|
198
|
+
(a, b) =>
|
|
199
|
+
parseSortableDate(b.updated_at || b.founded) -
|
|
200
|
+
parseSortableDate(a.updated_at || a.founded)
|
|
201
|
+
);
|
|
133
202
|
const tracker =
|
|
134
203
|
toplist?.toplist_bonus || toplist?.one_liner || toplist?.tracker || "main";
|
|
135
204
|
const noBonuses = useTranslate("noNewUpdates", "No new items");
|
|
@@ -149,6 +218,7 @@ const BonusesItems = ({ toplist, showUnread }) => {
|
|
|
149
218
|
showUnread={showUnread}
|
|
150
219
|
bonusCodeLabel={bonusCodeLabel}
|
|
151
220
|
updatedLabel={updatedLabel}
|
|
221
|
+
hideBadges={hideBadges}
|
|
152
222
|
/>
|
|
153
223
|
))}
|
|
154
224
|
</ul>
|
|
@@ -163,6 +233,7 @@ BonusesItems.propTypes = {
|
|
|
163
233
|
tracker: PropTypes.string,
|
|
164
234
|
}),
|
|
165
235
|
showUnread: PropTypes.bool,
|
|
236
|
+
hideBadges: PropTypes.bool
|
|
166
237
|
};
|
|
167
238
|
|
|
168
|
-
export default BonusesItems;
|
|
239
|
+
export default BonusesItems;
|
|
@@ -2,20 +2,28 @@
|
|
|
2
2
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
3
3
|
import React from "react";
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
|
+
import { FaArrowRight } from "@react-icons/all-files/fa/FaArrowRight";
|
|
5
6
|
import LazyImage from "~hooks/lazy-image";
|
|
6
7
|
import keygen from "~helpers/keygen";
|
|
7
8
|
import Link from "~hooks/link";
|
|
8
9
|
import {
|
|
9
10
|
imagePrettyUrl,
|
|
10
11
|
getExtraField,
|
|
11
|
-
textWordsLimit,
|
|
12
12
|
} from "~helpers/getters";
|
|
13
13
|
import { getAltText, getImageFilename } from "~helpers/image";
|
|
14
14
|
import ArticleIcon from "../../../../../images/icons/articleIcon";
|
|
15
15
|
import useTranslate from "~hooks/useTranslate/useTranslate";
|
|
16
|
-
import { getTimeAgo } from "~helpers/date-time";
|
|
16
|
+
import { getTimeAgo, parseSortableDate } from "~helpers/date-time";
|
|
17
17
|
import styles from "./notification-items.module.scss";
|
|
18
18
|
|
|
19
|
+
const getTrendingSortDate = (item) =>
|
|
20
|
+
parseSortableDate(
|
|
21
|
+
item?.manual_updated_date ||
|
|
22
|
+
item?.updated_at ||
|
|
23
|
+
item?.manual_published_date ||
|
|
24
|
+
item?.created_at
|
|
25
|
+
);
|
|
26
|
+
|
|
19
27
|
const CategoryTag = ({ category }) => {
|
|
20
28
|
const label = useTranslate(
|
|
21
29
|
`category_${category.short_name}`,
|
|
@@ -27,10 +35,11 @@ const CategoryTag = ({ category }) => {
|
|
|
27
35
|
return <span className={styles.tag}>{label}</span>;
|
|
28
36
|
};
|
|
29
37
|
|
|
30
|
-
const CardsItems = ({ module,
|
|
31
|
-
const
|
|
38
|
+
const CardsItems = ({ module, showUnread = false }) => {
|
|
39
|
+
const items = [...(module?.items || [])].sort(
|
|
40
|
+
(a, b) => getTrendingSortDate(b) - getTrendingSortDate(a)
|
|
41
|
+
);
|
|
32
42
|
const noNewUpdates = useTranslate("noNewUpdates", "No new items");
|
|
33
|
-
const updatedLabel = useTranslate("updated", "Updated");
|
|
34
43
|
|
|
35
44
|
const renderItem = (item) => {
|
|
36
45
|
const isArticleOrPage = ["article", "page"].includes(item?.relation_type);
|
|
@@ -46,20 +55,20 @@ const CardsItems = ({ module, wordLimit = 12, showUnread = false }) => {
|
|
|
46
55
|
const categories = item?.categories || [];
|
|
47
56
|
const description =
|
|
48
57
|
subtitle || item?.short_description || item?.description || "";
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
const dateModified = item?.manual_updated_date || item?.updated_at;
|
|
59
|
+
const datePublished = item?.manual_published_date || item?.created_at;
|
|
60
|
+
const dateString = dateModified || datePublished;
|
|
61
|
+
const usePublishedLabel = !dateModified && Boolean(datePublished);
|
|
62
|
+
const timeData = dateString ? getTimeAgo(dateString) : null;
|
|
63
|
+
const timeAgo = timeData?.value
|
|
64
|
+
? `${useTranslate(
|
|
65
|
+
usePublishedLabel ? "published" : "updated",
|
|
66
|
+
usePublishedLabel ? "Published" : "Updated"
|
|
67
|
+
)} ${timeData.value} ${useTranslate(
|
|
58
68
|
timeData.key,
|
|
59
69
|
timeData.key?.replace(/_/g, " ")
|
|
60
70
|
)}`
|
|
61
71
|
: "";
|
|
62
|
-
|
|
63
72
|
const thumbnail = img ? (
|
|
64
73
|
<LazyImage
|
|
65
74
|
width={40}
|
|
@@ -87,14 +96,13 @@ const CardsItems = ({ module, wordLimit = 12, showUnread = false }) => {
|
|
|
87
96
|
)}
|
|
88
97
|
{description && (
|
|
89
98
|
<p className={styles.subtitle}>
|
|
90
|
-
{
|
|
91
|
-
description.replace(/<\/?[^>]+(>|$)/g, ""),
|
|
92
|
-
wordLimit
|
|
93
|
-
)}
|
|
99
|
+
{description.replace(/<\/?[^>]+(>|$)/g, "")}
|
|
94
100
|
</p>
|
|
95
101
|
)}
|
|
96
102
|
</div>
|
|
97
|
-
<span className={styles.cta} aria-hidden="true"
|
|
103
|
+
<span className={styles.cta} aria-hidden="true">
|
|
104
|
+
<FaArrowRight size={12} />
|
|
105
|
+
</span>
|
|
98
106
|
</div>
|
|
99
107
|
{(categories.length > 0 || ribbon || timeAgo) && (
|
|
100
108
|
<div className={styles.meta}>
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
.unreadDot {
|
|
137
|
-
left: -
|
|
137
|
+
left: -0.8rem;
|
|
138
138
|
top: -0.8rem;
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -157,10 +157,6 @@
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
.text {
|
|
161
|
-
padding-right: 2.4rem;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
160
|
.title {
|
|
165
161
|
font-weight: 700;
|
|
166
162
|
color: var(--notification-oneliner-color, #1b1b1c);
|
|
@@ -169,6 +165,10 @@
|
|
|
169
165
|
.subtitle {
|
|
170
166
|
display: -webkit-box;
|
|
171
167
|
overflow: hidden;
|
|
168
|
+
-webkit-box-orient: vertical;
|
|
169
|
+
-webkit-line-clamp: 2;
|
|
170
|
+
line-clamp: 2;
|
|
171
|
+
text-overflow: ellipsis;
|
|
172
172
|
color: var(--notification-trending-description-color, #6e6e84);
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -206,15 +206,16 @@
|
|
|
206
206
|
flex-shrink: 0;
|
|
207
207
|
width: 3.6rem;
|
|
208
208
|
height: 3.6rem;
|
|
209
|
+
padding: 0.2rem 0.8rem 0.4rem;
|
|
210
|
+
border: var(--notification-panel-cta-border, none);
|
|
209
211
|
border-radius: var(--notification-cta-border-radius, 4.8rem);
|
|
210
|
-
background: var(--notification-trending-cta-bg, #f4f4f4)
|
|
211
|
-
|
|
212
|
-
no-repeat center;
|
|
212
|
+
background: var(--notification-trending-cta-bg, #f4f4f4);
|
|
213
|
+
color: var(--notification-trending-cta-color, #6b6a72);
|
|
213
214
|
pointer-events: none;
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
.embeddedList {
|
|
218
219
|
gap: 1.2rem;
|
|
219
|
-
padding: 0.8rem 0 0
|
|
220
|
+
padding: 0.8rem 0 0;
|
|
220
221
|
}
|
|
@@ -2,19 +2,29 @@
|
|
|
2
2
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
3
3
|
import React from "react";
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
|
-
import {
|
|
5
|
+
import { FaArrowRight } from "@react-icons/all-files/fa/FaArrowRight";
|
|
6
|
+
import { imagePrettyUrl } from "~helpers/getters";
|
|
6
7
|
import { getAltText, getImageFilename } from "~helpers/image";
|
|
7
8
|
import LazyImage from "~hooks/lazy-image";
|
|
8
9
|
import keygen from "~helpers/keygen";
|
|
9
10
|
import Link from "~hooks/link";
|
|
10
11
|
import useTranslate from "~hooks/useTranslate/useTranslate";
|
|
11
|
-
import { getTimeAgo } from "~helpers/date-time";
|
|
12
|
+
import { getTimeAgo, parseSortableDate } from "~helpers/date-time";
|
|
12
13
|
import styles from "../cards-v2/notification-items.module.scss";
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
-
|
|
15
|
+
const getTrendingSortDate = (item) =>
|
|
16
|
+
parseSortableDate(
|
|
17
|
+
item?.manual_updated_date ||
|
|
18
|
+
item?.updated_at ||
|
|
19
|
+
item?.manual_published_date ||
|
|
20
|
+
item?.created_at
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const SpotlightItems = ({ module, showUnread = false }) => {
|
|
24
|
+
const items = [...(module?.items || [])].sort(
|
|
25
|
+
(a, b) => getTrendingSortDate(b) - getTrendingSortDate(a)
|
|
26
|
+
);
|
|
16
27
|
const noNewUpdates = useTranslate("noNewUpdates", "No new items");
|
|
17
|
-
const updatedLabel = useTranslate("updated", "Updated");
|
|
18
28
|
|
|
19
29
|
const renderItem = (item) => {
|
|
20
30
|
const img = item?.image;
|
|
@@ -24,21 +34,24 @@ const SpotlightItems = ({ module, showUnread = false, wordLimit = 12 }) => {
|
|
|
24
34
|
const ribbon = item?.subtitle?.split(",")[0]?.replace("[null]", "")?.trim();
|
|
25
35
|
const metaText = item?.subtitle?.split(",").slice(1).join(",").trim();
|
|
26
36
|
const description = item?.short_description || item?.text || "";
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
const dateModified = item?.manual_updated_date || item?.updated_at;
|
|
38
|
+
const datePublished = item?.manual_published_date || item?.created_at;
|
|
39
|
+
const dateString = dateModified || datePublished;
|
|
40
|
+
const usePublishedLabel = !dateModified && Boolean(datePublished);
|
|
41
|
+
const timeData = dateString ? getTimeAgo(dateString) : null;
|
|
32
42
|
const timeKeyLabel = useTranslate(
|
|
33
|
-
timeData
|
|
34
|
-
timeData
|
|
43
|
+
timeData?.key,
|
|
44
|
+
timeData?.key?.replace(/_/g, " ")
|
|
35
45
|
);
|
|
36
46
|
let timeAgo = "";
|
|
37
47
|
|
|
38
|
-
if (timeData
|
|
39
|
-
timeAgo = `${
|
|
48
|
+
if (timeData?.value) {
|
|
49
|
+
timeAgo = `${useTranslate(
|
|
50
|
+
usePublishedLabel ? "published" : "updated",
|
|
51
|
+
usePublishedLabel ? "Published" : "Updated"
|
|
52
|
+
)} ${timeData.value} ${timeKeyLabel}`;
|
|
40
53
|
} else if (metaText) {
|
|
41
|
-
timeAgo = `${
|
|
54
|
+
timeAgo = `${useTranslate("updated", "Updated")} ${metaText}`;
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
return (
|
|
@@ -64,14 +77,13 @@ const SpotlightItems = ({ module, showUnread = false, wordLimit = 12 }) => {
|
|
|
64
77
|
)}
|
|
65
78
|
{description && (
|
|
66
79
|
<p className={styles.subtitle}>
|
|
67
|
-
{
|
|
68
|
-
description.replace(/<\/?[^>]+(>|$)/g, ""),
|
|
69
|
-
wordLimit
|
|
70
|
-
)}
|
|
80
|
+
{description.replace(/<\/?[^>]+(>|$)/g, "")}
|
|
71
81
|
</p>
|
|
72
82
|
)}
|
|
73
83
|
</div>
|
|
74
|
-
<span className={styles.cta} aria-hidden="true"
|
|
84
|
+
<span className={styles.cta} aria-hidden="true">
|
|
85
|
+
<FaArrowRight size={12} />
|
|
86
|
+
</span>
|
|
75
87
|
</div>
|
|
76
88
|
{(ribbon || timeAgo) && (
|
|
77
89
|
<div className={styles.meta}>
|
|
@@ -138,7 +150,6 @@ SpotlightItems.propTypes = {
|
|
|
138
150
|
items: PropTypes.arrayOf(PropTypes.shape({})),
|
|
139
151
|
}),
|
|
140
152
|
showUnread: PropTypes.bool,
|
|
141
|
-
wordLimit: PropTypes.number,
|
|
142
153
|
};
|
|
143
154
|
|
|
144
155
|
export default SpotlightItems;
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
height: calc(100% - var(--nav-height-mobile, 4.8rem));
|
|
63
63
|
background: var(--notification-panel-bg, #fff);
|
|
64
64
|
border-left: var(--notification-panel-border-left, 0 solid transparent);
|
|
65
|
+
border-top: var(--notification-panel-border-top, 0 solid transparent);
|
|
65
66
|
|
|
66
67
|
@include min(tablet) {
|
|
67
68
|
top: 0;
|
|
@@ -115,6 +116,7 @@
|
|
|
115
116
|
gap: 0.8rem;
|
|
116
117
|
padding: 0 0 0.8rem;
|
|
117
118
|
border-bottom: 1px solid var(--notification-item-border, #e3e6ef);
|
|
119
|
+
cursor: default;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
.unreadDot {
|
|
@@ -134,6 +136,7 @@
|
|
|
134
136
|
gap: 0.8rem;
|
|
135
137
|
width: 100%;
|
|
136
138
|
min-height: 5.2rem;
|
|
139
|
+
cursor: default;
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
.logo {
|
|
@@ -144,6 +147,7 @@
|
|
|
144
147
|
height: 5.2rem;
|
|
145
148
|
border: 1px solid var(--notification-logo-border, #dedede);
|
|
146
149
|
border-radius: var(--notification-logo-border-radius, 0.8rem);
|
|
150
|
+
cursor: default;
|
|
147
151
|
|
|
148
152
|
img {
|
|
149
153
|
display: block;
|
|
@@ -153,6 +157,7 @@
|
|
|
153
157
|
}
|
|
154
158
|
}
|
|
155
159
|
|
|
160
|
+
|
|
156
161
|
.bonusText {
|
|
157
162
|
@include flex-direction(column);
|
|
158
163
|
@include flex-align(flex-start, center);
|
|
@@ -161,6 +166,7 @@
|
|
|
161
166
|
min-width: 0;
|
|
162
167
|
gap: 0.4rem;
|
|
163
168
|
padding-right: 2.4rem;
|
|
169
|
+
cursor: default;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
.oneliner {
|
|
@@ -169,6 +175,7 @@
|
|
|
169
175
|
font-weight: 700;
|
|
170
176
|
line-height: 2.2rem;
|
|
171
177
|
color: var(--notification-oneliner-color, #1b1b1c);
|
|
178
|
+
cursor: default;
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
.bonusCodeRow {
|
|
@@ -210,15 +217,36 @@
|
|
|
210
217
|
|
|
211
218
|
svg {
|
|
212
219
|
flex-shrink: 0;
|
|
220
|
+
pointer-events: none;
|
|
213
221
|
color: var(--notification-bonus-code-icon, #262629);
|
|
214
222
|
}
|
|
215
223
|
}
|
|
216
224
|
|
|
225
|
+
.bonusCodeCopied {
|
|
226
|
+
border-color: var(--notification-bonus-code-border, #20cd77);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.bonusCodeCheckIcon {
|
|
230
|
+
@include flex-align(center, center);
|
|
231
|
+
|
|
232
|
+
flex-shrink: 0;
|
|
233
|
+
width: 2rem;
|
|
234
|
+
height: 2rem;
|
|
235
|
+
pointer-events: none;
|
|
236
|
+
|
|
237
|
+
svg {
|
|
238
|
+
display: block;
|
|
239
|
+
width: 2rem;
|
|
240
|
+
height: 2rem;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
217
244
|
.meta {
|
|
218
245
|
@include flex-align(center, flex-start);
|
|
219
246
|
|
|
220
247
|
width: 100%;
|
|
221
248
|
min-height: 1.8rem;
|
|
249
|
+
cursor: default;
|
|
222
250
|
}
|
|
223
251
|
|
|
224
252
|
.reviewLink {
|
|
@@ -229,6 +257,7 @@
|
|
|
229
257
|
line-height: 1.8rem;
|
|
230
258
|
color: var(--notification-link-color, #165af8);
|
|
231
259
|
text-decoration: underline;
|
|
260
|
+
cursor: pointer;
|
|
232
261
|
}
|
|
233
262
|
|
|
234
263
|
.updated {
|
|
@@ -240,6 +269,7 @@
|
|
|
240
269
|
color: var(--notification-meta-color, #515156);
|
|
241
270
|
text-align: right;
|
|
242
271
|
white-space: nowrap;
|
|
272
|
+
cursor: default;
|
|
243
273
|
}
|
|
244
274
|
|
|
245
275
|
.cta {
|
|
@@ -253,6 +283,7 @@
|
|
|
253
283
|
background: var(--notification-cta-bg, #6e33e5);
|
|
254
284
|
color: var(--notification-cta-color, #fff);
|
|
255
285
|
text-decoration: none;
|
|
286
|
+
cursor: default;
|
|
256
287
|
|
|
257
288
|
&:hover {
|
|
258
289
|
background: var(--notification-cta-hover-bg, #5a28c7);
|
|
@@ -270,3 +301,21 @@
|
|
|
270
301
|
text-decoration: none;
|
|
271
302
|
}
|
|
272
303
|
}
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
.customVerifiedBadge {
|
|
307
|
+
@include flex-align(center, flex-start);
|
|
308
|
+
|
|
309
|
+
box-sizing: border-box;
|
|
310
|
+
width: fit-content;
|
|
311
|
+
gap: 0.4rem;
|
|
312
|
+
height: 2rem;
|
|
313
|
+
padding: 0.1rem 0.6rem 0.1rem 0.2rem;
|
|
314
|
+
border-radius: var(--notification-badge-border-radius, 10rem);
|
|
315
|
+
font-size: 1.2rem;
|
|
316
|
+
font-weight: 400;
|
|
317
|
+
line-height: 1.8rem;
|
|
318
|
+
background: var(--notification-verified-badge-bg, #DEE9FF);
|
|
319
|
+
color: var(--notification-verified-badge-color, #000);
|
|
320
|
+
border: 1px solid var(--notification-verified-badge-border, transparent);
|
|
321
|
+
}
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
h2 {
|
|
11
11
|
flex: 1;
|
|
12
12
|
margin: 0;
|
|
13
|
-
font-size: 2rem;
|
|
13
|
+
font-size: var(--notification-panel-title-size, 2rem);
|
|
14
14
|
font-weight: 700;
|
|
15
|
-
line-height: 2.8rem;
|
|
15
|
+
line-height: var(--notification-panel-title-line-height, 2.8rem);
|
|
16
16
|
color: var(--notification-title-color, #0f0c28);
|
|
17
17
|
text-transform: capitalize;
|
|
18
18
|
}
|
|
@@ -5,7 +5,7 @@ import CountryFlagIcon from "~images/icons/countryFlag";
|
|
|
5
5
|
import useTranslate from "~hooks/useTranslate/useTranslate";
|
|
6
6
|
import styles from "./panel-tabs.module.scss";
|
|
7
7
|
|
|
8
|
-
const PanelTabs = ({ activeTab, onTabChange, market }) => {
|
|
8
|
+
const PanelTabs = ({ activeTab, onTabChange, market, hideBadges }) => {
|
|
9
9
|
const countryCode = market?.split("_")[0]?.toUpperCase();
|
|
10
10
|
const verifiedMonth = new Intl.DateTimeFormat("en-US", {
|
|
11
11
|
month: "long",
|
|
@@ -45,8 +45,7 @@ const PanelTabs = ({ activeTab, onTabChange, market }) => {
|
|
|
45
45
|
{trendingContentLabel}
|
|
46
46
|
</button>
|
|
47
47
|
</div>
|
|
48
|
-
|
|
49
|
-
{activeTab === "bonuses" && (
|
|
48
|
+
{(activeTab === "bonuses" && !hideBadges) && (
|
|
50
49
|
<div className={styles.badges}>
|
|
51
50
|
<span className={styles.verifiedBadge}>
|
|
52
51
|
<VerifiedBadgeIcon />
|
|
@@ -74,6 +73,7 @@ PanelTabs.propTypes = {
|
|
|
74
73
|
activeTab: PropTypes.oneOf(["bonuses", "trending"]).isRequired,
|
|
75
74
|
onTabChange: PropTypes.func.isRequired,
|
|
76
75
|
market: PropTypes.string,
|
|
76
|
+
hideBadges: PropTypes.bool
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
export default PanelTabs;
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
@include flex-align(flex-start, stretch);
|
|
12
12
|
|
|
13
13
|
box-sizing: border-box;
|
|
14
|
-
height: 4rem;
|
|
15
14
|
padding: 0.4rem;
|
|
16
15
|
border: 1px solid var(--notification-tabs-border, #dedede);
|
|
17
16
|
border-radius: var(--notification-tabs-border-radius, 1.2rem);
|
|
@@ -21,10 +20,9 @@
|
|
|
21
20
|
.tab,
|
|
22
21
|
.tabActive {
|
|
23
22
|
flex: 1;
|
|
24
|
-
height: 3.2rem;
|
|
25
23
|
border: 0;
|
|
26
24
|
border-radius: var(--notification-tab-border-radius, 0.8rem);
|
|
27
|
-
padding: 0.
|
|
25
|
+
padding: 0.7rem 1rem;
|
|
28
26
|
font-size: 1.2rem;
|
|
29
27
|
line-height: 1.8rem;
|
|
30
28
|
cursor: pointer;
|
package/src/helpers/date-time.js
CHANGED
|
@@ -52,3 +52,11 @@ export const getTimeAgo = (dateString) => {
|
|
|
52
52
|
}
|
|
53
53
|
return { value: diffMinutes, key: diffMinutes === 1 ? "minute_ago" : "minutes_ago" };
|
|
54
54
|
};
|
|
55
|
+
|
|
56
|
+
export const parseSortableDate = (dateString) => {
|
|
57
|
+
if (!dateString) return 0;
|
|
58
|
+
|
|
59
|
+
const time = Date.parse(String(dateString).replace(" ", "T"));
|
|
60
|
+
|
|
61
|
+
return Number.isNaN(time) ? 0 : time;
|
|
62
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatDate, getTimeAgo } from './date-time';
|
|
1
|
+
import { formatDate, getTimeAgo, parseSortableDate } from './date-time';
|
|
2
2
|
|
|
3
3
|
describe('Date-Time Helper', () => {
|
|
4
4
|
test('formatDate()', () => {
|
|
@@ -22,4 +22,11 @@ describe('Date-Time Helper', () => {
|
|
|
22
22
|
expect(getTimeAgo(daysAgo)).toMatchObject({ key: 'days_ago', value: 10 });
|
|
23
23
|
expect(getTimeAgo(monthsAgo)).toMatchObject({ key: 'months_ago', value: 2 });
|
|
24
24
|
});
|
|
25
|
+
|
|
26
|
+
test('parseSortableDate()', () => {
|
|
27
|
+
expect(parseSortableDate(null)).toBe(0);
|
|
28
|
+
expect(parseSortableDate('2025-06-01 10:00:00')).toBeGreaterThan(
|
|
29
|
+
parseSortableDate('2024-01-01 10:00:00')
|
|
30
|
+
);
|
|
31
|
+
});
|
|
25
32
|
});
|
|
@@ -6,7 +6,7 @@ export default function CheckCircleIcon({ width = 24, height = 24, color = '#272
|
|
|
6
6
|
<svg
|
|
7
7
|
width={width}
|
|
8
8
|
height={height}
|
|
9
|
-
viewBox=
|
|
9
|
+
viewBox="0 0 24 24"
|
|
10
10
|
fill="none"
|
|
11
11
|
aria-labelledby="checkCircleIcon"
|
|
12
12
|
xmlns="http://www.w3.org/2000/svg"
|
package/src/resolver/modules.mjs
CHANGED
|
@@ -520,6 +520,35 @@ export function shouldSavePrefilled(module = {}, siteName) {
|
|
|
520
520
|
);
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
+
function normalizePathForMatch(path) {
|
|
524
|
+
if (!path || typeof path !== "string") return "";
|
|
525
|
+
return path.replace(/^\/+|\/+$/g, "");
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function getSpotlightLinkedPage(link, pagesMappedById = {}) {
|
|
529
|
+
if (!link || link.type !== "page") return null;
|
|
530
|
+
|
|
531
|
+
if (link.page_id && pagesMappedById[link.page_id]) {
|
|
532
|
+
return pagesMappedById[link.page_id];
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const linkValue = link.value;
|
|
536
|
+
if (!linkValue) return null;
|
|
537
|
+
|
|
538
|
+
if (pagesMappedById[linkValue]) {
|
|
539
|
+
return pagesMappedById[linkValue];
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const linkPath = normalizePathForMatch(linkValue);
|
|
543
|
+
if (!linkPath) return null;
|
|
544
|
+
|
|
545
|
+
return (
|
|
546
|
+
Object.values(pagesMappedById).find(
|
|
547
|
+
(page) => normalizePathForMatch(page?.path) === linkPath
|
|
548
|
+
) || null
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
523
552
|
export function processSpotlightModule(module = {}, content, relations, ribbons, previewPageID, translations, relationData, operators, games,
|
|
524
553
|
pagesMappedById = {}
|
|
525
554
|
) {
|
|
@@ -543,11 +572,22 @@ export function processSpotlightModule(module = {}, content, relations, ribbons,
|
|
|
543
572
|
games
|
|
544
573
|
);
|
|
545
574
|
|
|
546
|
-
const
|
|
547
|
-
const linkedPage = pageId ? pagesMappedById[pageId] : null;
|
|
575
|
+
const linkedPage = getSpotlightLinkedPage(item?.link, pagesMappedById);
|
|
548
576
|
if (linkedPage?.short_description) {
|
|
549
577
|
item.short_description = linkedPage.short_description;
|
|
550
578
|
}
|
|
579
|
+
if (linkedPage?.updated_at) {
|
|
580
|
+
item.updated_at = linkedPage.updated_at;
|
|
581
|
+
}
|
|
582
|
+
if (linkedPage?.manual_updated_date) {
|
|
583
|
+
item.manual_updated_date = linkedPage.manual_updated_date;
|
|
584
|
+
}
|
|
585
|
+
if (linkedPage?.created_at) {
|
|
586
|
+
item.created_at = linkedPage.created_at;
|
|
587
|
+
}
|
|
588
|
+
if (linkedPage?.manual_published_date) {
|
|
589
|
+
item.manual_published_date = linkedPage.manual_published_date;
|
|
590
|
+
}
|
|
551
591
|
});
|
|
552
592
|
}
|
|
553
593
|
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
shouldSavePrefilled,
|
|
12
12
|
processContentModule,
|
|
13
13
|
processAnchor,
|
|
14
|
+
processSpotlightModule,
|
|
14
15
|
} from "./modules.mjs";
|
|
15
16
|
import { objectsHolder } from "~tests/factories/modules/modules.factory";
|
|
16
17
|
import getPageDataList from "~tests/factories/pages/list.factory";
|
|
@@ -391,4 +392,43 @@ expect(module.value.ribbons[0]).toBe("testRibbon");
|
|
|
391
392
|
|
|
392
393
|
expect(prefilledModule.items).toHaveLength(3);
|
|
393
394
|
});
|
|
395
|
+
|
|
396
|
+
test("Spotlights resolve linked page by path when page_id is missing", () => {
|
|
397
|
+
const linkedPage = {
|
|
398
|
+
...getPageData(),
|
|
399
|
+
id: 123,
|
|
400
|
+
path: "casino-bonus/irishlucks-exclusive-bonuses-vault",
|
|
401
|
+
updated_at: "2024-06-10 12:00:00",
|
|
402
|
+
short_description: "Linked page description",
|
|
403
|
+
};
|
|
404
|
+
const module = {
|
|
405
|
+
mode: "image_text",
|
|
406
|
+
items: [
|
|
407
|
+
{
|
|
408
|
+
label: "Bonus Club",
|
|
409
|
+
text: "<p>Join now!</p>",
|
|
410
|
+
link: {
|
|
411
|
+
type: "page",
|
|
412
|
+
value: "/casino-bonus/irishlucks-exclusive-bonuses-vault",
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
processSpotlightModule(
|
|
419
|
+
module,
|
|
420
|
+
{},
|
|
421
|
+
{},
|
|
422
|
+
{},
|
|
423
|
+
null,
|
|
424
|
+
{},
|
|
425
|
+
{},
|
|
426
|
+
{},
|
|
427
|
+
{},
|
|
428
|
+
{ 123: linkedPage }
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
expect(module.items[0].short_description).toBe("Linked page description");
|
|
432
|
+
expect(module.items[0].updated_at).toBe("2024-06-10 12:00:00");
|
|
433
|
+
});
|
|
394
434
|
});
|