gatsby-core-theme 44.3.1 → 45.0.0-beta.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +15 -154
  2. package/gatsby-node.mjs +4 -3
  3. package/package.json +1 -1
  4. package/src/components/atoms/admin/bar/layout-section/index.js +5 -5
  5. package/src/components/atoms/button/operator-cta.js +3 -1
  6. package/src/components/atoms/contact-form/contact-form.test.js +3 -3
  7. package/src/components/atoms/notifications/notification-items/cards-v2/index.js +33 -15
  8. package/src/components/molecules/bonus-box/template-one/index.js +0 -1
  9. package/src/components/molecules/bonus-box/template-three/index.js +1 -2
  10. package/src/components/molecules/comment/comment.module.scss +100 -0
  11. package/src/components/molecules/comment/index.js +65 -0
  12. package/src/components/molecules/floating-area/index.js +22 -22
  13. package/src/components/molecules/leave-comment-form/index.js +81 -0
  14. package/src/components/molecules/leave-comment-form/leave-comment-form.module.scss +23 -0
  15. package/src/components/molecules/module/index.js +2 -0
  16. package/src/components/organisms/comments/comment-tree/index.js +29 -0
  17. package/src/components/organisms/comments/index.js +26 -0
  18. package/src/components/organisms/cookie-consent/cookie-consent.module.scss +1 -2
  19. package/src/components/organisms/cookie-consent/index.js +1 -1
  20. package/src/components/organisms/search/index.js +14 -11
  21. package/src/components/organisms/search/variable/index.js +1 -1
  22. package/src/components/organisms/search/variable/searchVariable.test.js +2 -0
  23. package/src/constants/forms.js +52 -0
  24. package/src/constants/site-settings/main.mjs +1 -1
  25. package/src/constants/site-settings/navigation.js +0 -1
  26. package/src/context/MainProvider.js +4 -12
  27. package/src/helpers/date-time.js +0 -22
  28. package/src/helpers/date-time.test.js +1 -16
  29. package/src/helpers/getters.mjs +0 -17
  30. package/src/helpers/getters.test.js +0 -52
  31. package/src/resolver/archive.mjs +0 -1
  32. package/src/resolver/comments.mjs +27 -0
  33. package/src/resolver/common.mjs +1 -1
  34. package/src/resolver/index.mjs +33 -40
  35. package/src/resolver/modules.mjs +85 -116
  36. package/src/resolver/page.mjs +71 -71
  37. package/src/resolver/relations.mjs +0 -21
  38. package/src/resolver/sports-relations.mjs +0 -1
  39. package/src/services/api.mjs +5 -5
  40. package/src/services/fetch.mjs +11 -5
  41. package/static/images/anon-user.svg +15 -0
  42. package/src/resolver/build-toplist-filter.mjs +0 -66
  43. package/src/resolver/build-toplist-filter.test.js +0 -104
@@ -0,0 +1,81 @@
1
+ /* eslint-disable react-hooks/exhaustive-deps */
2
+ /* eslint-disable jsx-a11y/click-events-have-key-events */
3
+ /* eslint-disable import/no-extraneous-dependencies */
4
+ import React from 'react';
5
+
6
+ import Form from "gatsby-core-theme/src/components/organisms/form";
7
+ import PropTypes from 'prop-types';
8
+ import { FaArrowRight } from '@react-icons/all-files/fa/FaArrowRight';
9
+ import { commentForm } from '../../../constants/forms';
10
+ import styles from './leave-comment-form.module.scss';
11
+
12
+ const LeaveCommentForm = ({
13
+ page,
14
+ showLabels = true,
15
+ showButtonIcon = false,
16
+ buttonLabel = 'Add Comment',
17
+ submitUrl = `${process.env.GATSBY_API_URL}/v0.1/content/comments`,
18
+ successMessage = 'Comment Added',
19
+ failMessage = 'Comment Not Added',
20
+ validationMessage = 'Fill all required fields',
21
+ buttonIcon = <FaArrowRight fontSize={20} title="Right-pointing Arrow Icon" />,
22
+ }) => {
23
+ const activeMarket = page?.market;
24
+
25
+ const customSubmit = (form) => {
26
+ const formData = new FormData(form);
27
+ const data = Object.fromEntries(formData.entries());
28
+
29
+ // if(data?.["g-recaptcha-response"] === '') return;
30
+
31
+ data.reference_id = page?.id;
32
+ data.site_id = process.env.SITE_ID;
33
+ data.market_short_code = activeMarket;
34
+ delete data["g-recaptcha-response"];
35
+
36
+ return fetch(submitUrl, {
37
+ method: 'POST',
38
+ cache: 'no-cache',
39
+ headers: {
40
+ 'Content-Type': 'application/json',
41
+ Accept: 'application/json',
42
+ },
43
+ body: JSON.stringify(data),
44
+ });
45
+ };
46
+
47
+ return <div className={`${styles.commentFormContainer}`}>
48
+ <Form
49
+ formOptions={commentForm[activeMarket] || commentForm.default}
50
+ showLabels={showLabels}
51
+ hasButton
52
+ showButtonIcon={showButtonIcon}
53
+ buttonLabel={buttonLabel}
54
+ customeSubmit={customSubmit}
55
+ successMessage={successMessage}
56
+ failMessage={failMessage}
57
+ validationMessage={validationMessage}
58
+ path={page?.path}
59
+ buttonIcon={buttonIcon}
60
+ customClass={styles.commentForm || ''}
61
+ />
62
+ </div>
63
+ };
64
+
65
+ LeaveCommentForm.propTypes = {
66
+ page: PropTypes.shape({
67
+ market: PropTypes.string,
68
+ id: PropTypes.number,
69
+ path: PropTypes.string,
70
+ }).isRequired,
71
+ submitUrl: PropTypes.string,
72
+ successMessage: PropTypes.string,
73
+ failMessage: PropTypes.string,
74
+ validationMessage: PropTypes.string,
75
+ buttonLabel: PropTypes.string,
76
+ showButtonIcon: PropTypes.bool,
77
+ showLabels: PropTypes.bool,
78
+ buttonIcon: PropTypes.element,
79
+ };
80
+
81
+ export default LeaveCommentForm;
@@ -0,0 +1,23 @@
1
+ .commentForm{
2
+ background-color: transparent;
3
+ box-shadow: none;
4
+ padding: 0;
5
+ margin-top: 3.5rem;
6
+
7
+ > form{
8
+ display: grid;
9
+ grid-template-columns: 1fr 1fr;
10
+
11
+ > button{
12
+ border: .2rem solid #161128;
13
+ padding: 8px 16px;
14
+ width: auto;
15
+ margin-left: auto;
16
+ border-radius: 5rem;
17
+ font-size: 1.4rem;
18
+ font-weight: 700;
19
+ line-height: 2.2rem;
20
+ text-transform: capitalize;
21
+ }
22
+ }
23
+ }
@@ -61,6 +61,8 @@ const Modules = ({ module, page, pageContext, modulePosition }) => {
61
61
  return lazy(() => import("~molecules/bonus/template-one"));
62
62
  case "image":
63
63
  return lazy(() => import("~atoms/image"));
64
+ case "comments":
65
+ return lazy(() => import("~organisms/comments"));
64
66
  case "spotlights":
65
67
  if (module?.mode === "image_text") {
66
68
  if (module?.style === "template_two") {
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+
3
+ import PropTypes, { arrayOf } from 'prop-types';
4
+ import keygen from '~helpers/keygen';
5
+ import Comment from "../../../molecules/comment";
6
+
7
+ const CommentTree = React.memo(({ comment, authors, depth = 0 }) => (
8
+ <div key={keygen()} style={{ marginLeft: depth * 56 }}>
9
+ <Comment comment={comment} authors={authors} isReply={depth > 0} />
10
+ {comment.replies?.map(reply => (
11
+ <CommentTree
12
+ key={keygen()}
13
+ comment={reply}
14
+ authors={authors}
15
+ depth={depth + 1}
16
+ />
17
+ ))}
18
+ </div>
19
+ ));
20
+
21
+ CommentTree.propTypes = {
22
+ comment: PropTypes.shape({
23
+ replies: arrayOf(PropTypes.shape({}))
24
+ }),
25
+ authors: PropTypes.shape({}),
26
+ depth: PropTypes.number
27
+ };
28
+
29
+ export default CommentTree;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import CommentTree from './comment-tree';
4
+ import LeaveCommentForm from '../../molecules/leave-comment-form';
5
+
6
+ const Comments = ({ pageContext }) => {
7
+ const { comments, authors } = pageContext;
8
+ if(!comments) return;
9
+
10
+ return (
11
+ <div>
12
+ {comments.map((comment) => <CommentTree comment={comment} authors={authors} depth={0} />)}
13
+ <LeaveCommentForm page={pageContext.page} />
14
+ </div>
15
+ );
16
+ };
17
+
18
+ Comments.propTypes = {
19
+ pageContext: PropTypes.shape({
20
+ comments: PropTypes.arrayOf({}),
21
+ authors: PropTypes.shape({}),
22
+ page: PropTypes.shape({})
23
+ })
24
+ };
25
+
26
+ export default Comments;
@@ -44,9 +44,8 @@
44
44
  background-color: var(--primary-button-color, #6e33e5);
45
45
  }
46
46
  button {
47
- text-wrap: var(--cookie-consent-wrap-button, nowrap);
48
47
  height: var(--cookie-consent-button-height, 5.6rem);
49
- display: var(--cookie-consent-button-display, flex);
48
+ display: flex;
50
49
  border-radius: var(--cookie-consent-button-radius, 10rem);
51
50
  padding: var(--cookie-consent-button-padding, 1.6rem 2.4rem);
52
51
  font-size: var(--cookie-consent-button-size, 1.8rem);
@@ -52,7 +52,7 @@ const CookieConsent = ({
52
52
  };
53
53
 
54
54
  useEffect(() => {
55
- if (typeof window !== `undefined` && getCookie('showCookie') !== false) {
55
+ if (typeof window !== `undefined` && getCookie('showCookie') !== 'false') {
56
56
  setShowCookieConsent(true);
57
57
  }
58
58
  }, []);
@@ -81,8 +81,9 @@ const SearchForm = ({
81
81
  } else {
82
82
  const searchUrl =
83
83
  marketPrefix !== "/"
84
- ? `/${marketPrefix}/s${process.env.TRAILING_SLASH ? "/" : ""}?s=${e.target.value
85
- }`
84
+ ? `/${marketPrefix}/s${process.env.TRAILING_SLASH ? "/" : ""}?s=${
85
+ e.target.value
86
+ }`
86
87
  : `/s${process.env.TRAILING_SLASH ? "/" : ""}?s=${e.target.value}`;
87
88
  window.location = `${window.location.origin}${searchUrl}`;
88
89
  }
@@ -147,8 +148,9 @@ const SearchForm = ({
147
148
  type="button"
148
149
  aria-label={useTranslate("ariaLabel-search", "Search")}
149
150
  onClick={handleOnSearchIconClick}
150
- className={`${styles.searchButton || ""} ${localSearch && (styles.active || "")
151
- } search-gtm btn-cta`}
151
+ className={`${styles.searchButton || ""} ${
152
+ localSearch && (styles.active || "")
153
+ } search-gtm btn-cta`}
152
154
  disabled={isDisabled}
153
155
  >
154
156
  {searchIcon === null ? (
@@ -235,12 +237,13 @@ const SearchForm = ({
235
237
  const inputValue =
236
238
  searchInputRef.current?.value.trim();
237
239
  if (inputValue) {
238
- const url = `/s${process.env.TRAILING_SLASH
239
- ? "/"
240
- : ""
241
- }?s=${encodeURIComponent(
242
- inputValue
243
- )}`;
240
+ const url = `/s${
241
+ process.env.TRAILING_SLASH
242
+ ? "/"
243
+ : ""
244
+ }?s=${encodeURIComponent(
245
+ inputValue
246
+ )}`;
244
247
  window.location.href = url;
245
248
  }
246
249
  }}
@@ -269,7 +272,7 @@ const SearchForm = ({
269
272
  )}
270
273
  </div>
271
274
  )}
272
- {(showRecommendedCasinos || showTopSearches) && (!filteredData || filteredData.length === 0) && !autoCompleteLoading && (
275
+ {(showRecommendedCasinos || showTopSearches) && (
273
276
  <VariableComponent
274
277
  recommendedCasinos={recommendedCasinos}
275
278
  topSearches={topSearches}
@@ -28,7 +28,7 @@ const VariableComponent = ({
28
28
  >
29
29
  {showTopSearches && (
30
30
  <div className={styles.topSearches}>
31
- <p>{useTranslate("top_searches_bar", "Top Searches:")}</p>
31
+ <p>Top Searches:</p>
32
32
  {topSearches?.map((item) => (
33
33
  <Link key={item.id} to={item?.link?.value}>
34
34
  {item?.label}
@@ -29,6 +29,8 @@ describe("VariableComponent", () => {
29
29
  />
30
30
  );
31
31
 
32
+ expect(screen.getByText("Top Searches:")).toBeInTheDocument();
33
+
32
34
  topSearches.forEach((item) => {
33
35
  expect(screen.getByText(item.label)).toBeInTheDocument();
34
36
  });
@@ -83,6 +83,58 @@ export const contactUsForm = {
83
83
  },
84
84
  };
85
85
 
86
+ export const commentForm = {
87
+ default: {
88
+ title: {
89
+ label: 'Leave a comment',
90
+ translationKey: 'leave_a_comment',
91
+ },
92
+ hasReCAPTCHA: true,
93
+ reCaptcha: {
94
+ // validations: {
95
+ // label: 'Please confirm',
96
+ // translationKey: 'valid_recaptcha',
97
+ // icon: <IoMdCloseCircleOutline />,
98
+ // }
99
+ },
100
+ fields: [
101
+ {
102
+ label: 'Name',
103
+ translationKey: 'name_label',
104
+ id: 'name',
105
+ type: 'text',
106
+ placeholder: {
107
+ label: 'Name',
108
+ translationKey: 'name_placeholder',
109
+ },
110
+ twoCol: true,
111
+ },
112
+ {
113
+ label: 'Email Address',
114
+ id: 'email',
115
+ type: 'email',
116
+ placeholder: {
117
+ label: 'Email@placeholder.com',
118
+ translationKey: 'email_placeholder',
119
+ },
120
+ translationKey: 'email_label',
121
+ twoCol: true,
122
+ },
123
+ {
124
+ id: 'comment',
125
+ type: 'textarea',
126
+ placeholder: {
127
+ label: 'Leave a comment',
128
+ translationKey: 'comment_placeholder',
129
+ },
130
+ translationKey: 'textarea_label',
131
+ maxLength: '1000',
132
+ twoCol: false,
133
+ },
134
+ ],
135
+ },
136
+ };
137
+
86
138
  export const newsLetterForm = {
87
139
  default: {
88
140
  title: {
@@ -15,7 +15,7 @@ export const mainSettings = {
15
15
  article: {
16
16
  reading_time: {
17
17
  "spielhallen.com": true,
18
- "demo-rocket-theme.gigmedia.com": true,
18
+ "demo-matrix-theme.gigmedia.com": true,
19
19
  default: false,
20
20
  },
21
21
  },
@@ -34,7 +34,6 @@ export const pageTypes = {
34
34
  showLogoWithLink: true,
35
35
  disableSearch: false,
36
36
  showNotification: true,
37
- showScrollToTop: true,
38
37
  customComponent: true,
39
38
  exclusiveOperator: true,
40
39
  navMenu: "main_menu",
@@ -1,20 +1,13 @@
1
1
  /* eslint-disable react/prop-types */
2
- import React, { createContext, useState } from "react";
2
+ import React, { createContext, useState } from 'react';
3
3
 
4
4
  export const Context = createContext();
5
5
 
6
6
  export default (props) => {
7
7
  const { value, children } = props;
8
8
 
9
- const [showTranslationKeys, setShowTranslationKeys] = useState(false);
10
- const [showFilter, setShowFilter] = useState(false);
11
- const [topListFilters, setTopListFilters] = useState();
12
- const topListContext = {
13
- showFilter,
14
- setShowFilter,
15
- topListFilters,
16
- setTopListFilters,
17
- };
9
+ const [ showTranslationKeys, setShowTranslationKeys ] = useState(false);
10
+
18
11
  return (
19
12
  <Context.Provider
20
13
  value={{
@@ -22,9 +15,8 @@ export default (props) => {
22
15
  preview: value.isPreview,
23
16
  language: value.language,
24
17
  admin: value.admin,
25
- setShowTranslationKeys,
26
18
  showTranslationKeys,
27
- topListContext,
19
+ setShowTranslationKeys
28
20
  }}
29
21
  >
30
22
  {children}
@@ -28,25 +28,3 @@ export function formatDate(date, format, separator = '/', market = 'en-GB') {
28
28
  }
29
29
  return formattedDate;
30
30
  }
31
-
32
- export const getTimeAgo = (dateString) => {
33
- const date = new Date(dateString.replace(" ", "T")); // Make it ISO-compliant
34
- const now = new Date();
35
-
36
- const diffMs = now.getTime() - date.getTime();
37
- const diffMinutes = Math.floor(diffMs / (1000 * 60));
38
- const diffHours = Math.floor(diffMinutes / 60);
39
- const diffDays = Math.floor(diffHours / 24);
40
- const diffMonths = Math.floor(diffDays / 30);
41
-
42
- if (diffDays >= 32) {
43
- return { value: diffMonths, key: diffMonths === 1 ? "month_ago" : "months_ago" };
44
- }
45
- if (diffDays >= 1) {
46
- return { value: diffDays, key: diffDays === 1 ? "day_ago" : "days_ago" };
47
- }
48
- if (diffHours >= 1) {
49
- return { value: diffHours, key: diffHours === 1 ? "hour_ago" : "hours_ago" };
50
- }
51
- return { value: diffMinutes, key: diffMinutes === 1 ? "minute_ago" : "minutes_ago" };
52
- };
@@ -1,4 +1,4 @@
1
- import { formatDate, getTimeAgo } from './date-time';
1
+ import { formatDate } from './date-time';
2
2
 
3
3
  describe('Date-Time Helper', () => {
4
4
  test('formatDate()', () => {
@@ -7,19 +7,4 @@ describe('Date-Time Helper', () => {
7
7
  expect(formatDate('2020-04-23 11:45:10', 'MMM YYYY', '/', 'en-US')).toEqual('April 2020');
8
8
  expect(formatDate('2020-04-23 11:45:10', 'DD/MM/YYYY', '@@', 'en-US')).toEqual('04@@23@@2020');
9
9
  });
10
-
11
-
12
- test('getTimeAgo()', () => {
13
- const now = new Date();
14
-
15
- const minutesAgo = new Date(now.getTime() - 5 * 60 * 1000).toISOString(); // 5 minutes ago
16
- const hoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000).toISOString(); // 2 hours ago
17
- const daysAgo = new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000).toISOString(); // 10 days ago
18
- const monthsAgo = new Date(now.getTime() - 65 * 24 * 60 * 60 * 1000).toISOString(); // ~2 months ago
19
-
20
- expect(getTimeAgo(minutesAgo)).toMatchObject({ key: 'minutes_ago', value: 5 });
21
- expect(getTimeAgo(hoursAgo)).toMatchObject({ key: 'hours_ago', value: 2 });
22
- expect(getTimeAgo(daysAgo)).toMatchObject({ key: 'days_ago', value: 10 });
23
- expect(getTimeAgo(monthsAgo)).toMatchObject({ key: 'months_ago', value: 2 });
24
- });
25
10
  });
@@ -241,23 +241,6 @@ export function getBonus(name, operator) {
241
241
  return null;
242
242
  }
243
243
 
244
- export function getPromoCode(item, tracker) {
245
-
246
- if (!item) {
247
- return null;
248
- }
249
- if (
250
- item.bonuses &&
251
- item.bonuses.hasOwnProperty(tracker) &&
252
- item.bonuses[tracker].promo_code !== ""
253
- ) {
254
-
255
-
256
- return item.bonuses[tracker].promo_code;
257
- }
258
- return null;
259
- }
260
-
261
244
  export function getGameExtraField(relation, key) {
262
245
  if (
263
246
  relation &&
@@ -502,56 +502,4 @@ describe('Getters Helper', () => {
502
502
  test('should handle null content', () => {
503
503
  expect(Getters.trailingSlash(null)).toBeNull();
504
504
  });
505
- test("returns null if item is null", () => {
506
- expect(Getters.getPromoCode(null, "main")).toBeNull();
507
- });
508
-
509
- test("returns null if bonuses object is missing", () => {
510
- const item = {};
511
- expect(Getters.getPromoCode(item, "main")).toBeNull();
512
- });
513
-
514
- test("returns null if promo code is an empty string", () => {
515
- const item = {
516
- bonuses: {
517
- main: {
518
- promo_code: "",
519
- },
520
- },
521
- };
522
- expect(Getters.getPromoCode(item, "main")).toBeNull();
523
- });
524
-
525
- test("returns correct promo code when it exists for tracker", () => {
526
- const item = {
527
- bonuses: {
528
- main: {
529
- promo_code: "PROMO123",
530
- },
531
- },
532
- };
533
- expect(Getters.getPromoCode(item, "main")).toBe("PROMO123");
534
- });
535
-
536
- test("returns null if tracker does not exist in bonuses", () => {
537
- const item = {
538
- bonuses: {
539
- other: {
540
- promo_code: "SOMECODE",
541
- },
542
- },
543
- };
544
- expect(Getters.getPromoCode(item, "main")).toBeNull();
545
- });
546
-
547
- test("returns correct promo code for non-main tracker", () => {
548
- const item = {
549
- bonuses: {
550
- exclusive: {
551
- promo_code: "EXCL2025",
552
- },
553
- },
554
- };
555
- expect(Getters.getPromoCode(item, "exclusive")).toBe("EXCL2025");
556
- });
557
505
  });
@@ -191,7 +191,6 @@ export const getArchivePages = (
191
191
 
192
192
  pagesToCreate.push({
193
193
  path: page.path,
194
- component: `${__dirname}/src/components/app.js`,
195
194
  context: {
196
195
  page,
197
196
  marketSections,
@@ -0,0 +1,27 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export function transformComments(comments) {
3
+ const transformedComments = {};
4
+
5
+ for (const comment of Object.values(comments || {})) {
6
+ const refId = comment.reference_id;
7
+ if (!transformedComments[refId]) {
8
+ transformedComments[refId] = [];
9
+ }
10
+ if(comment.approved){
11
+ transformedComments[refId].push({
12
+ replies: transformComments(comment?.replies)[refId],
13
+ email: comment?.email,
14
+ name: comment?.name,
15
+ comment: comment?.comment,
16
+ rate: comment?.rate,
17
+ author_id: comment?.author_id,
18
+ votes_down: comment.votes_down,
19
+ votes_up: comment.votes_up,
20
+ created_at: comment?.created_at,
21
+ updated_at: comment?.updated_at,
22
+ });
23
+ }
24
+ }
25
+
26
+ return transformedComments;
27
+ }
@@ -171,7 +171,7 @@ export function removeUnwantedSections(obj, pageType, ribbonsData) {
171
171
  ]);
172
172
 
173
173
  // Filter the object to retain only the sections in the sectionsToKeep set
174
- const filteredObject = Object.keys(obj || {}).reduce((acc, key) => {
174
+ const filteredObject = Object.keys(obj).reduce((acc, key) => {
175
175
  if (sectionsToKeep.has(key)) {
176
176
  acc[key] = obj[key];
177
177