gatsby-core-theme 44.27.0 → 44.29.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 +28 -0
- package/package.json +1 -1
- package/src/components/atoms/notifications/index.js +110 -38
- package/src/components/atoms/notifications/notification-items/bonuses/bonuses.test.js +63 -0
- package/src/components/atoms/notifications/notification-items/bonuses/index.js +168 -0
- package/src/components/atoms/notifications/notification-items/cards-v2/index.js +102 -90
- package/src/components/atoms/notifications/notification-items/cards-v2/notification-items.module.scss +165 -215
- package/src/components/atoms/notifications/notification-items/spotlight/index.js +111 -83
- package/src/components/atoms/notifications/notifications.module.scss +267 -19
- package/src/components/atoms/notifications/notifications.test.js +10 -4
- package/src/components/atoms/notifications/panel-header/index.js +45 -0
- package/src/components/atoms/notifications/panel-header/panel-header.module.scss +51 -0
- package/src/components/atoms/notifications/panel-tabs/index.js +79 -0
- package/src/components/atoms/notifications/panel-tabs/panel-tabs.module.scss +115 -0
- package/src/components/molecules/newsletter/toggle-button/index.js +4 -2
- package/src/components/organisms/navigation/index.js +6 -1
- package/src/constants/pick-keys.mjs +2 -0
- package/src/images/icons/copyIcon.js +26 -0
- package/src/images/icons/countryFlag.js +19 -0
- package/src/images/icons/verifiedBadgeIcon.js +35 -0
- package/src/resolver/index.mjs +10 -7
- package/src/resolver/modules.mjs +11 -2
- package/src/components/atoms/notifications/notification-items/spotlight/notification-items.module.scss +0 -271
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
# [44.29.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.28.0...v44.29.0) (2026-06-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* refactor notification panel code ([073b7ca](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/073b7ca9ff3f4c978b161b32a470fc01e6a9ab03))
|
|
7
|
+
* show the inactive casino in the search page but no in the autocomplete ([fc03761](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/fc037613b1ed9941d58f4a4f8787780ad381bab8))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
* Merge branch 'master' of gitlab.com:g2m-gentoo/team-floyd/themes/gatsby-themes ([efb9e68](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/efb9e68764108c499c2e264009b5c0cbd7814171))
|
|
11
|
+
* Merge branch 'EN-536/notification-panel' into 'master' ([f94a556](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/f94a556a1f11e582f15b57307d749b926b2b7869))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* add more variables and country flag icon ([8f2051a](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/8f2051a3817d3406fb96c0346c16e4608a403f2f))
|
|
17
|
+
* update notification panel ([3315645](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/3315645a744dd61c651260224db1197717a86ffa))
|
|
18
|
+
|
|
19
|
+
# [44.28.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.27.0...v44.28.0) (2026-06-17)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
* Merge branch 'update-newsletter' into 'master' ([e1b2c7e](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/e1b2c7e0490c9ef1c929049e20d7ff28d1d71b9d))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* update newsletter button ([063907c](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/commit/063907c743eea01d39155344c750831a42d0de5d))
|
|
28
|
+
|
|
1
29
|
# [44.27.0](https://gitlab.com/g2m-gentoo/team-floyd/themes/gatsby-themes/compare/v44.26.2...v44.27.0) (2026-06-16)
|
|
2
30
|
|
|
3
31
|
|
package/package.json
CHANGED
|
@@ -3,27 +3,63 @@ import PropTypes from "prop-types";
|
|
|
3
3
|
import { toggleScroll } from "~helpers/scroll";
|
|
4
4
|
import { NavigationContext } from "~organisms/navigation/navigationContext";
|
|
5
5
|
import SpotlightItems from "./notification-items/spotlight";
|
|
6
|
+
import BonusesItems from "./notification-items/bonuses";
|
|
6
7
|
import CardsItems from "./notification-items/cards-v2";
|
|
8
|
+
import PanelHeader from "./panel-header";
|
|
9
|
+
import PanelTabs from "./panel-tabs";
|
|
7
10
|
import BellIcon from "~images/icons/bell";
|
|
8
11
|
import CloseIcon from "~images/icons/closeIcon";
|
|
9
|
-
import styles from "./notifications.module.scss";
|
|
10
12
|
import useTranslate from "../../../hooks/useTranslate/useTranslate";
|
|
13
|
+
import styles from "./notifications.module.scss";
|
|
14
|
+
|
|
15
|
+
const getNotificationToplist = (modules) => {
|
|
16
|
+
const toplistModule = modules.find((m) => m.name === "top_list");
|
|
17
|
+
if (!toplistModule) return null;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
toplistModule.items?.find(
|
|
21
|
+
(item) =>
|
|
22
|
+
item.value === "notification_panel_toplist" ||
|
|
23
|
+
item.short_name === "notification_panel_toplist"
|
|
24
|
+
) ?? toplistModule.items?.[0]
|
|
25
|
+
);
|
|
26
|
+
};
|
|
11
27
|
|
|
12
|
-
const Notifications = ({ section }) => {
|
|
28
|
+
const Notifications = ({ section, market }) => {
|
|
13
29
|
const { setShowSearch, setShowMenu, showMenu, showSearch } =
|
|
14
30
|
useContext(NavigationContext);
|
|
15
31
|
const notificationRef = useRef(null);
|
|
16
32
|
const [newNotification, setNewNotification] = useState(true);
|
|
17
33
|
const [openNotification, setOpenNotification] = useState(false);
|
|
18
34
|
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
const modules = section?.modules || [];
|
|
36
|
+
const notificationToplist = getNotificationToplist(modules);
|
|
37
|
+
const cardsModule = modules.find((m) => m.name === "cards_v2");
|
|
38
|
+
const spotlightModule = modules.find((m) => m.name === "spotlights");
|
|
39
|
+
|
|
40
|
+
const [activeTab, setActiveTab] = useState(
|
|
41
|
+
notificationToplist?.items?.length ? "bonuses" : "trending"
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const renderTrendingContent = () => {
|
|
45
|
+
if (cardsModule) {
|
|
46
|
+
return (
|
|
47
|
+
<CardsItems
|
|
48
|
+
module={cardsModule}
|
|
49
|
+
showUnread={newNotification}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<SpotlightItems
|
|
56
|
+
module={spotlightModule}
|
|
57
|
+
showUnread={newNotification}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
24
61
|
|
|
25
62
|
const notificationActions = () => {
|
|
26
|
-
setNewNotification(false);
|
|
27
63
|
setOpenNotification(!openNotification);
|
|
28
64
|
|
|
29
65
|
if (showSearch) {
|
|
@@ -36,6 +72,14 @@ const Notifications = ({ section }) => {
|
|
|
36
72
|
}
|
|
37
73
|
};
|
|
38
74
|
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!openNotification) return undefined;
|
|
77
|
+
|
|
78
|
+
toggleScroll("notifications");
|
|
79
|
+
|
|
80
|
+
return () => toggleScroll("notifications");
|
|
81
|
+
}, [openNotification]);
|
|
82
|
+
|
|
39
83
|
useEffect(() => {
|
|
40
84
|
function handleClickOutside(event) {
|
|
41
85
|
if (
|
|
@@ -46,51 +90,79 @@ const Notifications = ({ section }) => {
|
|
|
46
90
|
}
|
|
47
91
|
}
|
|
48
92
|
|
|
49
|
-
// Bind the event listener
|
|
50
93
|
document.addEventListener("mousedown", handleClickOutside);
|
|
94
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
95
|
+
}, []);
|
|
51
96
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
97
|
+
const bellAriaLabel = useTranslate(
|
|
98
|
+
"ariaLabel-notificationBellIcon",
|
|
99
|
+
"Notification Bell Icon"
|
|
100
|
+
);
|
|
101
|
+
const closeLabel = useTranslate("close", "Close");
|
|
57
102
|
|
|
58
103
|
return (
|
|
59
|
-
<div ref={notificationRef} className={styles
|
|
104
|
+
<div ref={notificationRef} className={styles.notificationOuter}>
|
|
60
105
|
<div
|
|
61
|
-
className={`${styles.notificationIcon
|
|
62
|
-
newNotification ? styles.newNotification
|
|
106
|
+
className={`${styles.notificationIcon} ${
|
|
107
|
+
newNotification ? styles.newNotification : ""
|
|
63
108
|
} notification-bell-gtm`}
|
|
64
|
-
onKeyDown={
|
|
65
|
-
onClick={
|
|
109
|
+
onKeyDown={notificationActions}
|
|
110
|
+
onClick={notificationActions}
|
|
66
111
|
role="button"
|
|
67
|
-
aria-label={
|
|
68
|
-
"ariaLabel-notificationBellIcon",
|
|
69
|
-
"Notification Bell Icon"
|
|
70
|
-
)}
|
|
112
|
+
aria-label={bellAriaLabel}
|
|
71
113
|
tabIndex={0}
|
|
72
114
|
>
|
|
73
|
-
{openNotification ?
|
|
74
|
-
|
|
75
|
-
{openNotification &&
|
|
76
|
-
(getNotifications()?.name === "cards_v2" ? (
|
|
77
|
-
<CardsItems
|
|
78
|
-
module={getNotifications()}
|
|
79
|
-
onClose={() => notificationActions()}
|
|
80
|
-
/>
|
|
115
|
+
{openNotification ? (
|
|
116
|
+
<CloseIcon color="var(--notification-bell-color, #1c1a28)" />
|
|
81
117
|
) : (
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
<BellIcon color="var(--notification-bell-color, #1c1a28)" />
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{openNotification && (
|
|
123
|
+
<div className={styles.container}>
|
|
124
|
+
<div
|
|
125
|
+
className={styles.overlay}
|
|
126
|
+
onKeyDown={notificationActions}
|
|
127
|
+
onClick={notificationActions}
|
|
128
|
+
role="button"
|
|
129
|
+
aria-label={closeLabel}
|
|
130
|
+
tabIndex={0}
|
|
131
|
+
/>
|
|
132
|
+
<div className={styles.panel}>
|
|
133
|
+
<PanelHeader
|
|
134
|
+
onClose={notificationActions}
|
|
135
|
+
onMarkAllRead={() => setNewNotification(false)}
|
|
136
|
+
/>
|
|
137
|
+
|
|
138
|
+
<PanelTabs
|
|
139
|
+
activeTab={activeTab}
|
|
140
|
+
onTabChange={setActiveTab}
|
|
141
|
+
market={market}
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
<div className={styles.content}>
|
|
145
|
+
{activeTab === "bonuses" ? (
|
|
146
|
+
<BonusesItems
|
|
147
|
+
toplist={notificationToplist}
|
|
148
|
+
showUnread={newNotification}
|
|
149
|
+
/>
|
|
150
|
+
) : (
|
|
151
|
+
renderTrendingContent()
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
87
157
|
</div>
|
|
88
158
|
);
|
|
89
159
|
};
|
|
90
160
|
|
|
91
161
|
Notifications.propTypes = {
|
|
92
|
-
|
|
93
|
-
section: PropTypes.shape({
|
|
162
|
+
market: PropTypes.string,
|
|
163
|
+
section: PropTypes.shape({
|
|
164
|
+
modules: PropTypes.arrayOf(PropTypes.shape({})),
|
|
165
|
+
}),
|
|
94
166
|
};
|
|
95
167
|
|
|
96
168
|
export default Notifications;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
4
|
+
import { getListToplistItem } from '~tests/factories/modules/toplist.factory';
|
|
5
|
+
import BonusesItems from '.';
|
|
6
|
+
|
|
7
|
+
const buildToplist = (overrides = {}) => ({
|
|
8
|
+
tracker: 'main',
|
|
9
|
+
items: getListToplistItem(1).map((item) => ({
|
|
10
|
+
...item,
|
|
11
|
+
updated_at: '2025-01-14 11:04:49',
|
|
12
|
+
logo: { filename: 'logo1.jpg' },
|
|
13
|
+
bonuses: {
|
|
14
|
+
main: {
|
|
15
|
+
...item.bonuses.main,
|
|
16
|
+
promo_code: 'BONUS123',
|
|
17
|
+
terms_and_conditions_enabled: true,
|
|
18
|
+
terms_and_conditions: 'Terms apply',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
})),
|
|
22
|
+
...overrides,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('BonusesItems', () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
Object.assign(navigator, {
|
|
28
|
+
clipboard: { writeText: jest.fn() },
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('renders empty state when toplist has no items', () => {
|
|
33
|
+
render(<BonusesItems toplist={{ items: [] }} />);
|
|
34
|
+
expect(screen.getByText('No new items')).toBeVisible();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('renders bonus item with promo code and copies on click', () => {
|
|
38
|
+
const toplist = buildToplist();
|
|
39
|
+
const { container } = render(<BonusesItems toplist={toplist} showUnread />);
|
|
40
|
+
|
|
41
|
+
expect(container.querySelector('.bonusList')).toBeVisible();
|
|
42
|
+
expect(container.querySelector('.unreadDot')).toBeVisible();
|
|
43
|
+
expect(screen.getByText('Bonus Code:')).toBeVisible();
|
|
44
|
+
expect(screen.getByText('BONUS123')).toBeVisible();
|
|
45
|
+
|
|
46
|
+
fireEvent.click(screen.getByText('BONUS123'));
|
|
47
|
+
expect(navigator.clipboard.writeText).toHaveBeenCalledWith('BONUS123');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('renders bonus item without promo code row', () => {
|
|
51
|
+
const toplist = buildToplist({
|
|
52
|
+
items: getListToplistItem(1).map((item) => ({
|
|
53
|
+
...item,
|
|
54
|
+
updated_at: '2025-01-14 11:04:49',
|
|
55
|
+
logo: { filename: 'logo1.jpg' },
|
|
56
|
+
})),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const { container } = render(<BonusesItems toplist={toplist} />);
|
|
60
|
+
expect(container.querySelector('.bonusCodeRow')).toBeFalsy();
|
|
61
|
+
expect(screen.getByText('name1 Review')).toBeVisible();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { FaArrowRight } from "@react-icons/all-files/fa/FaArrowRight";
|
|
4
|
+
import CopyIcon from "~images/icons/copyIcon";
|
|
5
|
+
import LazyImage from "~hooks/lazy-image";
|
|
6
|
+
import PrettyLink from "~atoms/pretty-link";
|
|
7
|
+
import ReviewLink from "~atoms/review-link";
|
|
8
|
+
import Tnc from "~molecules/tnc";
|
|
9
|
+
import keygen from "~helpers/keygen";
|
|
10
|
+
import {
|
|
11
|
+
getBonusData,
|
|
12
|
+
getPromoCode,
|
|
13
|
+
imagePrettyUrl,
|
|
14
|
+
} from "~helpers/getters";
|
|
15
|
+
import { getAltText } from "~helpers/image";
|
|
16
|
+
import { getTimeAgo } from "~helpers/date-time";
|
|
17
|
+
import { TrackingKeys } from "~constants/tracking-api";
|
|
18
|
+
import useTranslate from "~hooks/useTranslate/useTranslate";
|
|
19
|
+
import styles from "../../notifications.module.scss";
|
|
20
|
+
|
|
21
|
+
const BonusItem = ({
|
|
22
|
+
item,
|
|
23
|
+
index,
|
|
24
|
+
tracker,
|
|
25
|
+
showUnread,
|
|
26
|
+
bonusCodeLabel,
|
|
27
|
+
updatedLabel,
|
|
28
|
+
}) => {
|
|
29
|
+
const bonus = getBonusData(item, tracker);
|
|
30
|
+
const oneliner = [bonus?.mainLine, bonus?.secondLine]
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.join(" + ");
|
|
33
|
+
const promoCode = getPromoCode(item, tracker);
|
|
34
|
+
const reviewPath = item.review_link
|
|
35
|
+
? `/${item.review_link}`
|
|
36
|
+
: item.path || null;
|
|
37
|
+
const timeData = getTimeAgo(item.updated_at) || {};
|
|
38
|
+
const timeKeyLabel = useTranslate(
|
|
39
|
+
timeData.key,
|
|
40
|
+
timeData.key?.replace(/_/g, " ")
|
|
41
|
+
);
|
|
42
|
+
const timeAgo = timeData.value
|
|
43
|
+
? `${updatedLabel} ${timeData.value} ${timeKeyLabel}`
|
|
44
|
+
: "";
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<li className={styles.bonusItem}>
|
|
48
|
+
{showUnread && <span className={styles.unreadDot} />}
|
|
49
|
+
<div className={styles.bonusTopRow}>
|
|
50
|
+
<PrettyLink
|
|
51
|
+
operator={item}
|
|
52
|
+
tracker={tracker}
|
|
53
|
+
moduleName={TrackingKeys.NAVIGATIONTOPLIST}
|
|
54
|
+
clickedElement="operator_logo"
|
|
55
|
+
className={styles.logo}
|
|
56
|
+
itemPosition={index + 1}
|
|
57
|
+
>
|
|
58
|
+
<LazyImage
|
|
59
|
+
width={52}
|
|
60
|
+
height={52}
|
|
61
|
+
alt={getAltText(item.logo, item.name)}
|
|
62
|
+
src={imagePrettyUrl(item.logo?.filename, 52, 52)}
|
|
63
|
+
/>
|
|
64
|
+
</PrettyLink>
|
|
65
|
+
|
|
66
|
+
<div className={styles.bonusText}>
|
|
67
|
+
{oneliner && <p className={styles.oneliner}>{oneliner}</p>}
|
|
68
|
+
{promoCode && (
|
|
69
|
+
<div className={styles.bonusCodeRow}>
|
|
70
|
+
<span className={styles.bonusCodeLabel}>{bonusCodeLabel}</span>
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
className={styles.bonusCode}
|
|
74
|
+
onClick={() => navigator.clipboard.writeText(promoCode)}
|
|
75
|
+
>
|
|
76
|
+
<span>{promoCode}</span>
|
|
77
|
+
<CopyIcon width={20} height={20} />
|
|
78
|
+
</button>
|
|
79
|
+
</div>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<PrettyLink
|
|
84
|
+
operator={item}
|
|
85
|
+
tracker={tracker}
|
|
86
|
+
moduleName={TrackingKeys.NAVIGATIONTOPLIST}
|
|
87
|
+
clickedElement="notification_cta"
|
|
88
|
+
className={styles.cta}
|
|
89
|
+
itemPosition={index + 1}
|
|
90
|
+
>
|
|
91
|
+
<FaArrowRight size={12} />
|
|
92
|
+
</PrettyLink>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div className={styles.meta}>
|
|
96
|
+
{reviewPath && (
|
|
97
|
+
<ReviewLink
|
|
98
|
+
className={styles.reviewLink}
|
|
99
|
+
operatorName={item.name}
|
|
100
|
+
reviewPath={reviewPath}
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
{timeAgo && <span className={styles.updated}>{timeAgo}</span>}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div className={styles.legal}>
|
|
107
|
+
<Tnc operator={item} tracker={tracker} isFixed />
|
|
108
|
+
</div>
|
|
109
|
+
</li>
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
BonusItem.propTypes = {
|
|
114
|
+
item: PropTypes.shape({
|
|
115
|
+
review_link: PropTypes.string,
|
|
116
|
+
path: PropTypes.string,
|
|
117
|
+
updated_at: PropTypes.string,
|
|
118
|
+
short_name: PropTypes.string,
|
|
119
|
+
name: PropTypes.string,
|
|
120
|
+
logo: PropTypes.shape({
|
|
121
|
+
filename: PropTypes.string,
|
|
122
|
+
}),
|
|
123
|
+
}).isRequired,
|
|
124
|
+
index: PropTypes.number.isRequired,
|
|
125
|
+
tracker: PropTypes.string.isRequired,
|
|
126
|
+
showUnread: PropTypes.bool,
|
|
127
|
+
bonusCodeLabel: PropTypes.string.isRequired,
|
|
128
|
+
updatedLabel: PropTypes.string.isRequired,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const BonusesItems = ({ toplist, showUnread }) => {
|
|
132
|
+
const items = toplist?.items || [];
|
|
133
|
+
const tracker =
|
|
134
|
+
toplist?.toplist_bonus || toplist?.one_liner || toplist?.tracker || "main";
|
|
135
|
+
const noBonuses = useTranslate("noNewUpdates", "No new items");
|
|
136
|
+
const bonusCodeLabel = useTranslate("bonus_code", "Bonus Code:");
|
|
137
|
+
const updatedLabel = useTranslate("updated", "Updated");
|
|
138
|
+
|
|
139
|
+
if (!items.length) return <p className={styles.empty}>{noBonuses}</p>;
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<ul className={styles.bonusList}>
|
|
143
|
+
{items.map((item, index) => (
|
|
144
|
+
<BonusItem
|
|
145
|
+
key={item.short_name || keygen()}
|
|
146
|
+
item={item}
|
|
147
|
+
index={index}
|
|
148
|
+
tracker={tracker}
|
|
149
|
+
showUnread={showUnread}
|
|
150
|
+
bonusCodeLabel={bonusCodeLabel}
|
|
151
|
+
updatedLabel={updatedLabel}
|
|
152
|
+
/>
|
|
153
|
+
))}
|
|
154
|
+
</ul>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
BonusesItems.propTypes = {
|
|
159
|
+
toplist: PropTypes.shape({
|
|
160
|
+
items: PropTypes.arrayOf(PropTypes.shape({})),
|
|
161
|
+
toplist_bonus: PropTypes.string,
|
|
162
|
+
one_liner: PropTypes.string,
|
|
163
|
+
tracker: PropTypes.string,
|
|
164
|
+
}),
|
|
165
|
+
showUnread: PropTypes.bool,
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export default BonusesItems;
|