gatsby-core-theme 6.1.2 → 6.1.8

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 CHANGED
@@ -1,3 +1,76 @@
1
+ ## [6.1.8](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v6.1.7...v6.1.8) (2022-04-26)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add operator related to the page as the first item in the comparison table automatically ([1fed78a](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/1fed78afc28bb072420556896dd350bb7351b69d))
7
+ * add unit testing ([a0d4f03](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/a0d4f0352553280e80ce08e3b8c533c78ffb6dfc))
8
+ * change map to find ([756e648](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/756e6481ef95b7b080c0e0c1fdbcc0c0caabd8fb))
9
+ * cleanup code ([c3f76aa](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/c3f76aa2866fa0011e8323c2a61e5ec5d815006e))
10
+ * include module introduction on all modules ([d9e0d01](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/d9e0d016503f0afee00cfe1724db48179b77020d))
11
+
12
+
13
+ ### Code Refactoring
14
+
15
+ * add condition for null module ([369fa6e](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/369fa6ec03b789a08542092c1355ab835d07cd14))
16
+ * fix typo ([e3248a3](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/e3248a306a12f6a27112ab9515ffb2484590ffe5))
17
+
18
+
19
+ * Merge branch 'tm-2823-removing-review' into 'master' ([5a1301c](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/5a1301c75bcad1b055918d024358f93295c3e1a6))
20
+ * Merge branch 'tm-2689-add-paragraph' into 'master' ([2cf135d](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/2cf135dd4619e1a1698aacdeb08a85c10ce70be2))
21
+
22
+ ## [6.1.7](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v6.1.6...v6.1.7) (2022-04-19)
23
+
24
+
25
+ ### Code Refactoring
26
+
27
+ * update cards, cards_v2 filtering for operator pages ([08ecad7](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/08ecad782f75f6f8105f203e06baf48951d68789))
28
+
29
+
30
+ * Merge branch 'tm-2805-cards-random-filter' into 'master' ([206b0e8](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/206b0e89234188e5a0ad38ad1fd1aec3a1212e89))
31
+
32
+
33
+ ### refactoe
34
+
35
+ * update processor modules tests ([11fd5a0](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/11fd5a0f7dcadf71a9550c58eeed383db35437e4))
36
+
37
+ ## [6.1.6](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v6.1.5...v6.1.6) (2022-04-18)
38
+
39
+
40
+ ### Bug Fixes
41
+
42
+ * commit to trigger publish ([6c6c3fb](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/6c6c3fb19ff72f175da8843c02cc467033211097))
43
+
44
+ ## [6.1.5](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v6.1.4...v6.1.5) (2022-04-18)
45
+
46
+
47
+ ### Bug Fixes
48
+
49
+ * changed npm token ([eba1721](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/eba17217edfaa65a57f0fc911341ae040df4e2df))
50
+
51
+
52
+ * Merge branch 'master' of git.ilcd.rocks:team-floyd/themes/gatsby-themes ([44e4e94](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/44e4e940745311f4435de7e965394481a0e13e21))
53
+
54
+ ## [6.1.4](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v6.1.3...v6.1.4) (2022-04-18)
55
+
56
+
57
+ ### Bug Fixes
58
+
59
+ * changed tracker ([4ed35aa](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/4ed35aa6ccdad19fdf9e203da67a8a74d78fd662))
60
+
61
+
62
+ * Merge branch 'master' of git.ilcd.rocks:team-floyd/themes/gatsby-themes ([43f8dcf](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/43f8dcf4f647f3f7128c10bfcc73482876129890))
63
+
64
+ ## [6.1.3](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v6.1.2...v6.1.3) (2022-04-18)
65
+
66
+
67
+ ### Bug Fixes
68
+
69
+ * star rating fixed design ([eaf7472](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/eaf74723c83f203e465d5cc3811cca562134b3ef))
70
+
71
+
72
+ * Merge branch 'tm-2783-fix-star-rating' into 'master' ([3f1d310](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/commit/3f1d3105db166d2bbdd48c2a2d19bb0c1e3a462e))
73
+
1
74
  ## [6.1.2](https://git.ilcd.rocks/team-floyd/themes/gatsby-themes/compare/v6.1.1...v6.1.2) (2022-04-13)
2
75
 
3
76
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gatsby-core-theme",
3
- "version": "6.1.2",
3
+ "version": "6.1.8",
4
4
  "description": "Gatsby Theme NPM Package",
5
5
  "main": "index.js",
6
6
  "GATSBY_RECAPTCHA_SITEKEY": "6LfoyvMUAAAAAO4nl_MQnqHb4XdHxEiu5cXgIqeB",
@@ -1,3 +1,4 @@
1
+ /* eslint-disable react/no-danger */
1
2
  /* eslint-disable react/prop-types */
2
3
  import React from 'react';
3
4
  import PropTypes from 'prop-types';
@@ -10,13 +11,15 @@ import { prettyTracker } from '~helpers/getters';
10
11
 
11
12
  const Modules = ({ module, page, pageContext }) => {
12
13
  const GetModuleComponent = (moduleItem) => {
13
- switch (moduleItem.name) {
14
+ const { items, name } = moduleItem || {};
15
+
16
+ switch (name) {
14
17
  case 'content':
15
18
  return loadable(() => import('~molecules/content'));
16
19
  case 'top_list':
17
20
  return loadable(() => import('~organisms/toplist'));
18
21
  case 'archive':
19
- if (!moduleItem.items || moduleItem.items.length === 0) return null;
22
+ if (!items || items.length === 0) return null;
20
23
  return loadable(() => import('~organisms/archive'));
21
24
  case 'counter':
22
25
  return loadable(() => import('~molecules/counter'));
@@ -28,14 +31,14 @@ const Modules = ({ module, page, pageContext }) => {
28
31
  case 'accordion':
29
32
  return loadable(() => import('~organisms/accordion'));
30
33
  case 'anchor':
31
- if (moduleItem.items && moduleItem.items.length > 0) {
34
+ if (items && items.length > 0) {
32
35
  return loadable(() => import('~organisms/anchor'));
33
36
  }
34
37
  return null;
35
38
  case 'carousel':
36
39
  if (
37
- moduleItem.items.length > 0 && // has items
38
- moduleItem.items.filter((item) => item.image === null).length === 0 // not filled with null items
40
+ items.length > 0 && // has items
41
+ items.filter((item) => item.image === null).length === 0 // not filled with null items
39
42
  ) {
40
43
  return loadable(() => import('~organisms/carousel'));
41
44
  }
@@ -79,6 +82,9 @@ const Modules = ({ module, page, pageContext }) => {
79
82
  } ${styles.module} ${module?.style && styles[module.style]} module`}
80
83
  >
81
84
  <ModuleTitle module={module} />
85
+ {module.module_introduction && (
86
+ <div dangerouslySetInnerHTML={{ __html: module?.module_introduction }} />
87
+ )}
82
88
  <ModuleComponent module={module} page={page} pageContext={pageContext} {...extraProps} />
83
89
  </div>
84
90
  )
@@ -1,14 +1,15 @@
1
1
  .starRatingContainer {
2
2
  @include flex-direction(row);
3
- @include flex-align(center, center);
3
+ justify-content: center;
4
4
  background-color: #ffffff;
5
5
  min-width: 6.5rem;
6
6
  min-height: 2.1rem;
7
+ line-height: 2.1rem;
7
8
  border-radius: 0.4rem;
8
9
  border: 1px solid var(--main-star-wrapper-color);
9
10
 
10
11
  .fullStar {
11
- @include star(var(--full-star-fill-color), var(--full-star-border-color));
12
+ @include star(var(--full-star-fill-color), var(--full-star-border-color), unset, 2.1rem);
12
13
  }
13
14
 
14
15
  .rateNr {
@@ -16,11 +17,12 @@
16
17
  font-weight: 700;
17
18
  font-size: 1.3rem;
18
19
  margin-left: 0.33rem;
20
+ line-height: 2.1rem;
19
21
  }
20
22
 
21
23
  &.inactive {
22
24
  .fullStar {
23
- @include star(var(--empty-star-border-color), var(--empty-star-border-color));
25
+ @include star(var(--empty-star-border-color), var(--empty-star-border-color), unset, 2.1rem);
24
26
  }
25
27
  }
26
28
  }
@@ -31,8 +31,8 @@ export function getExtraField(extraFields, key, defaultValue) {
31
31
  }
32
32
 
33
33
  export function getSection(shortCode, pageContext) {
34
- const page = pageContext?.page;
35
- const marketSections = pageContext?.marketSections;
34
+ const page = pageContext && pageContext.page;
35
+ const marketSections = pageContext && pageContext.marketSections;
36
36
  // eslint-disable-next-line
37
37
  if (!page || !page.hasOwnProperty('sections') || !page.sections.hasOwnProperty(shortCode)) {
38
38
  return null;
@@ -91,7 +91,7 @@ export function image(filename, width, height, fit = 'cover') {
91
91
  }
92
92
 
93
93
  export function getImageFilename(src) {
94
- const srcArr = src?.substring(src?.lastIndexOf('/') + 1)?.split('.');
94
+ const srcArr = src && src.substring(src.lastIndexOf('/') + 1).split('.');
95
95
  if (!srcArr.length) {
96
96
  return '';
97
97
  }
@@ -321,7 +321,7 @@ export function copyrightText() {
321
321
  }
322
322
 
323
323
  export function getFirstModuleByName(section, moduleName) {
324
- if (section && section.modules && section.modules[0]?.name === moduleName) {
324
+ if (section && section.modules && section.modules[0].name === moduleName) {
325
325
  return section.modules[0];
326
326
  }
327
327
  return null;
@@ -329,7 +329,7 @@ export function getFirstModuleByName(section, moduleName) {
329
329
 
330
330
  export function translate(translations, key, defaultValue = '') {
331
331
  // eslint-disable-next-line
332
- if (translations?.hasOwnProperty(key)) {
332
+ if (translations && translations.hasOwnProperty(key)) {
333
333
  return translations[key];
334
334
  }
335
335
  return defaultValue;
@@ -338,3 +338,27 @@ export function translate(translations, key, defaultValue = '') {
338
338
  export function getAws(imageName) {
339
339
  return `https://assets-srv.s3.eu-west-1.amazonaws.com/${imageName}`;
340
340
  }
341
+
342
+ // This part of the code, help us to add operator related to the page as the first item in the comparison table automatically
343
+ // example: if we are on the operator review page(Rizk) that should be first in the comparison table
344
+ // First, we check if we have that item in the array, if that item is in the array, we check its position
345
+ // If the item isn't in the array we will add it automatically
346
+ export function shiftFirstOperator(pageId, module, pagesMappedById) {
347
+ let index = null;
348
+ // check if exist that element in array
349
+ const checkIfExistElement = module.items.find((item, i) => {
350
+ if (item.id === pageId) {
351
+ index = i;
352
+ if (index > 0) {
353
+ // eslint-disable-next-line no-nested-ternary
354
+ module.items.sort((x, y) => (x.id === pageId ? -1 : y.id === pageId ? 1 : 0));
355
+ }
356
+ return true;
357
+ }
358
+ return false;
359
+ });
360
+ if (!checkIfExistElement) {
361
+ // eslint-disable-next-line no-unused-expressions
362
+ pagesMappedById[pageId] && module.items.unshift(pagesMappedById[pageId]);
363
+ }
364
+ }
@@ -1,4 +1,5 @@
1
1
  import * as Getters from './getters';
2
+ import pagesMappedById from '../../tests/factories/pagesMappedById';
2
3
 
3
4
  describe('Getters Helper', () => {
4
5
  const { location } = window;
@@ -228,4 +229,28 @@ describe('Getters Helper', () => {
228
229
  expect(Getters.translate(object, 'hello')).toEqual('world');
229
230
  expect(Getters.translate(object, 'foo', 'bar')).toEqual('bar');
230
231
  });
232
+
233
+ const module = {
234
+ items: [
235
+ {
236
+ id: 12300,
237
+ },
238
+ {
239
+ id: 13212,
240
+ },
241
+ ],
242
+ };
243
+
244
+ test('add the operator item', () => {
245
+ Getters.shiftFirstOperator(11607, module, pagesMappedById);
246
+ expect(module.items[0].id).toBe(11607);
247
+ });
248
+ test('move opeartor first postion', () => {
249
+ Getters.shiftFirstOperator(13212, module, pagesMappedById);
250
+ expect(module.items[0].id).toBe(13212);
251
+ });
252
+ test('check when we have the operator in first postion', () => {
253
+ Getters.shiftFirstOperator(13212, module, pagesMappedById);
254
+ expect(module.items[0].id).toBe(13212);
255
+ });
231
256
  });
@@ -78,6 +78,10 @@ export function transform(response) {
78
78
  const savedModules = {};
79
79
  export function processSections(sections, skipPost = false, page) {
80
80
  const siteName = page && page.siteInfo && page.siteInfo.site_name;
81
+
82
+ // pagedId we will use it just on operator review pages
83
+ const pageId = page && page.type === 'operator' ? page.id : null;
84
+
81
85
  let minutes = 0;
82
86
  let seconds = 0;
83
87
 
@@ -100,7 +104,8 @@ export function processSections(sections, skipPost = false, page) {
100
104
  relations,
101
105
  pagesMappedById,
102
106
  menus,
103
- previewMode
107
+ previewMode,
108
+ pageId
104
109
  );
105
110
 
106
111
  if (shouldSavePrefilled(module, siteName)) {
@@ -5,6 +5,7 @@ import { clonePageForCards, groupBy, removeDuplicates } from './common';
5
5
  import settings from '../../constants/settings';
6
6
  import ModuleValue from '../../constants/module-value';
7
7
  import { topListPickKeys } from '../../constants/pick-keys';
8
+ import { shiftFirstOperator } from '../getters';
8
9
 
9
10
  const pagesGroupedByTemplateId = [];
10
11
 
@@ -18,9 +19,15 @@ export function processCardsModule(module, pages, pagesCloned, pagesMappedById)
18
19
  const numOfItems =
19
20
  Math.sign(module.num_of_items) === 0 ? pages[modelType].length : Number(module.num_of_items);
20
21
  if (sortBy === 'random') {
21
- const samplePages = pagesCloned[modelType].filter(
22
- (page) => !settings.filter_cards_modules[process.env.GATSBY_SITE_NAME].includes(page.status)
23
- );
22
+ const samplePages =
23
+ module.cards_page_type !== 'operator'
24
+ ? pagesCloned[modelType]
25
+ : pagesCloned[modelType].filter(
26
+ (page) =>
27
+ !settings.filter_cards_modules[process.env.GATSBY_SITE_NAME].includes(
28
+ page.relation && page.relation.status
29
+ )
30
+ );
24
31
  module.items = sampleSize(samplePages, numOfItems);
25
32
  } else {
26
33
  module.items = pagesCloned[modelType].slice(0, numOfItems);
@@ -99,16 +106,18 @@ export function filterOperators(pages, selectedProviders, selectedTypes) {
99
106
  return pagesFiltered;
100
107
  }
101
108
 
102
- export function processCardsV2(module, pagesCloned, pagesMappedById) {
109
+ export function processCardsV2(module, pagesCloned, pagesMappedById, pageId) {
103
110
  const pageType = module.cards_page_type;
104
111
  const pageTemplateId = module.cards_page_type_id;
105
112
  const sortType = module.cards_selector_filters_sort_by;
106
113
  const cardSelector = module.cards_selector;
114
+ const styleName = module.style;
107
115
  const moduleSelectedProviders =
108
116
  module.cards_selector_filters && module.cards_selector_filters.providers;
109
117
  const moduleSelectedCategories =
110
118
  module.cards_selector_filters && module.cards_selector_filters.categories;
111
119
  const moduleSelectedTypes = module.cards_selector_filters && module.cards_selector_filters.types;
120
+
112
121
  module.items = [];
113
122
 
114
123
  if (cardSelector === 'select_manually') {
@@ -180,10 +189,15 @@ export function processCardsV2(module, pagesCloned, pagesMappedById) {
180
189
 
181
190
  // Applying sorting
182
191
  if (sortType === 'random') {
183
- const samplePages = uniquePages.filter(
184
- (page) =>
185
- !settings.filter_cards_modules[process.env.GATSBY_SITE_NAME].includes(page.status)
186
- );
192
+ const samplePages =
193
+ module.cards_page_type !== 'operator'
194
+ ? uniquePages
195
+ : uniquePages.filter(
196
+ (page) =>
197
+ !settings.filter_cards_modules[process.env.GATSBY_SITE_NAME].includes(
198
+ page.relation && page.relation.status
199
+ )
200
+ );
187
201
  module.items = sampleSize(samplePages, itemLimit);
188
202
  } else if (sortType === 'latest') {
189
203
  if (uniquePages.length > 0) {
@@ -193,6 +207,11 @@ export function processCardsV2(module, pagesCloned, pagesMappedById) {
193
207
  }
194
208
  }
195
209
  }
210
+
211
+ if (styleName === 'comparison_table' && pageId !== null) {
212
+ shiftFirstOperator(pageId, module, pagesMappedById);
213
+ }
214
+
196
215
  // modify page so it doesn't have too much data
197
216
  module.items = module.items.map((item) => clonePageForCards(cloneDeep(item), module.style));
198
217
  }
@@ -238,12 +257,13 @@ export function processModule(
238
257
  relations,
239
258
  pagesMappedById,
240
259
  menus,
241
- previewMode
260
+ previewMode,
261
+ pageId
242
262
  ) {
243
263
  if (module.name === 'cards') {
244
264
  processCardsModule(module, pages, pagesCloned, pagesMappedById);
245
265
  } else if (module.name === 'cards_v2') {
246
- processCardsV2(module, pagesCloned, pagesMappedById);
266
+ processCardsV2(module, pagesCloned, pagesMappedById, pageId);
247
267
  } else if (module.name === 'bonus') {
248
268
  processBonus(module, relations);
249
269
  } else if (module.name === 'archive' && previewMode) {
@@ -17,6 +17,11 @@ import {
17
17
  import { relationData, singleToplistData } from '../../../tests/factories/modules/toplist.factory';
18
18
 
19
19
  describe('Modules Helper', () => {
20
+ beforeEach(() => {
21
+ jest.resetModules();
22
+ process.env = { ...process.env };
23
+ delete process.env.NODE_ENV;
24
+ });
20
25
  test('Cards V2 Manual list', () => {
21
26
  const pagesNum = 10;
22
27
  const moduleData = getSampleCardsV2ModuleManual();
@@ -45,12 +50,14 @@ describe('Modules Helper', () => {
45
50
  const moduleData = getSampleCardsV2Filtered(false, 'Game');
46
51
  moduleData.cards_selector_filters_sort_by = 'random';
47
52
  moduleData.cards_selector_filters_limit = '3';
53
+ moduleData.cards_page_type = 'operator';
48
54
  const pageList = getPageDataList(pagesNum).map((page, i) =>
49
55
  i % 2
50
- ? { ...page, type: 'game', status: 'inactive' }
51
- : { ...page, type: 'game', status: 'active' }
56
+ ? { ...page, type: 'operator', relation: { ...page.relation, status: 'inactive' } }
57
+ : { ...page, type: 'operator', relation: { ...page.relation, status: 'active' } }
52
58
  );
53
- processCardsV2(moduleData, groupBy(pageList, 'type'));
59
+ const { processCardsV2: processCardsV2Clean } = require('./modules');
60
+ processCardsV2Clean(moduleData, groupBy(pageList, 'type'), groupBy(pageList, 'id'));
54
61
 
55
62
  expect(moduleData.items).toHaveLength(3);
56
63
  moduleData.items.forEach((item) => {
@@ -67,7 +67,7 @@
67
67
  border-top: $height solid $color;
68
68
  border-right: calc($width / 2) solid transparent;
69
69
  border-left: calc($width / 2) solid transparent;
70
- margin-left: - calc($width / 2);
70
+ margin-left: -calc($width / 2);
71
71
  }
72
72
  }
73
73
 
@@ -85,9 +85,9 @@
85
85
  }
86
86
  }
87
87
 
88
- @mixin star($border-color: #fba62f, $fill-color: #fba62f) {
89
- line-height: 2rem;
90
- width: 16px;
88
+ @mixin star($border-color: #ffb400, $fill-color: #ffb400, $width: 16px, $line-height: 2rem) {
89
+ line-height: $line-height;
90
+ width: $width;
91
91
  font-weight: normal;
92
92
  display: inline-block;
93
93
  color: $fill-color;
@@ -103,7 +103,7 @@
103
103
  }
104
104
  }
105
105
 
106
- @mixin half-star($border-color: #fba62f, $half-empty-color: #fba62f, $half-full-color: white) {
106
+ @mixin half-star($border-color: #ffb400, $half-empty-color: #ffb400, $half-full-color: white) {
107
107
  line-height: 2rem;
108
108
  width: 16px;
109
109
  font-weight: normal;
package/storybook/.ci.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  # ######################
2
- # STORYBOOK CI
2
+ # STORYBOOK
3
3
  # #####################
4
4
 
5
5
  Storybook Build:
@@ -9,7 +9,7 @@ Storybook Build:
9
9
  - floyd-runner-test
10
10
  script:
11
11
  - yarn config set cache-folder .yarn
12
- - npm config set //registry.npmjs.org/:_authToken 32bb5578-6354-4c61-8d7a-d49a4869bc21
12
+ - npm config set //registry.npmjs.org/:_authToken $NPM_AUTH_TOKEN
13
13
  - yarn
14
14
  - yarn workspace gatsby-core-theme build-storybook -o ./storybook/public
15
15
  artifacts:
@@ -0,0 +1,117 @@
1
+ export default {
2
+ 11607: {
3
+ id: 11607,
4
+ market_id: 7,
5
+ updated_at: '2021-10-28',
6
+ created_at: '2020-02-14 14:12:45',
7
+ template_id: 11,
8
+ page_hreflang_group_id: null,
9
+ page_hreflang_combined: 0,
10
+ relation_id: 3148,
11
+ relation_type: 'game',
12
+ market: 'no_no',
13
+ region_code: null,
14
+ crawler_location_market: null,
15
+ author: {
16
+ name: 'Ida Moen Olsen',
17
+ profile_page_path: 'om-oss/ida-moen-olsen',
18
+ image_asset_id: 64615,
19
+ image_alt: null,
20
+ site_id: 2,
21
+ country_id: null,
22
+ language_id: null,
23
+ twitter_profile: null,
24
+ facebook_profile: null,
25
+ linkedin_profile: null,
26
+ instagram_profile: null,
27
+ personal_website: null,
28
+ email_address: null,
29
+ author_title: null,
30
+ additional_url: null,
31
+ image: 'ida-moen-olsen.webp',
32
+ image_object: [],
33
+ country: null,
34
+ language: null,
35
+ },
36
+ reviewer: null,
37
+ hard_coded_breadcrumbs: 0,
38
+ breadcrumb_ids: [174],
39
+ categories: [],
40
+ author_id: 47,
41
+ reviewer_id: null,
42
+ style_id: null,
43
+ language: 'no',
44
+ description: null,
45
+ meta_title: "Caishen's Arrival - Norske Spilleautomater",
46
+ meta_robots: null,
47
+ robot_options: {
48
+ page_index: 1,
49
+ links_followed: 1,
50
+ images_index: 1,
51
+ show_snippet: 1,
52
+ },
53
+ meta_description:
54
+ 'Caishens Arrival er en asiatisk inspirert automat med gratisspinn og en massiv multiplikator på x 35,000. Du kan spille automaten gratis her',
55
+ page_custom_hreflangs: null,
56
+ title: "Caishen's Arrival",
57
+ vanity_label: null,
58
+ path: 'caishens-arrival-spilleautomater',
59
+ type: 'game',
60
+ template: 'game_review',
61
+ banner: '5af66017a898b7a5d6349b9396c1c680.jpeg',
62
+ featured_image: '5af66017a898b7a5d6349b9396c1c680.jpeg',
63
+ canonical_url: null,
64
+ canonical_url_page_id: null,
65
+ status: 'active',
66
+ page_group_id: null,
67
+ page_group_combined: 0,
68
+ page_group_custom_items: null,
69
+ sections: {
70
+ main: [],
71
+ header: [],
72
+ navigation: null,
73
+ footer: null,
74
+ post_main_games: null,
75
+ },
76
+ featured_image_object: {
77
+ width: '400',
78
+ height: '250',
79
+ url: 'https://assets-srv.s3.eu-west-1.amazonaws.com/5af66017a898b7a5d6349b9396c1c680.jpeg',
80
+ filename: '5af66017a898b7a5d6349b9396c1c680.jpeg',
81
+ },
82
+ relation: {
83
+ id: 3148,
84
+ name: "Caishen's Arrival",
85
+ short_name: 'caishens_arrival',
86
+ first_rating: '2',
87
+ second_rating: '4',
88
+ third_rating: '4',
89
+ fourth_rating: '2',
90
+ average_rating: '',
91
+ volatility: 2,
92
+ iframe: '',
93
+ freespins: 1,
94
+ rtp: 95.74,
95
+ launch_date: '2019-10-16',
96
+ number_of_reels: 5,
97
+ winning_lines: 25,
98
+ jackpots: 0,
99
+ vegas: 0,
100
+ fruit: 0,
101
+ wilds: 0,
102
+ sticky_wilds: 0,
103
+ respins: 0,
104
+ mega_ways: 0,
105
+ bonus_rounds: 0,
106
+ recommended: 0,
107
+ exclusive: 0,
108
+ new: 0,
109
+ hot: 0,
110
+ game_provider: [],
111
+ markets: [],
112
+ enabled: true,
113
+ game_categories: [],
114
+ game_screenshots: [],
115
+ },
116
+ },
117
+ };