@everymatrix/casino-filter-page 0.0.365 → 0.0.367

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.
@@ -1,535 +1,535 @@
1
- <svelte:options tag={null} />
2
-
3
- <script lang="ts">
4
- import { onMount } from "svelte";
5
- import { isMobile, getDevice } from 'rvhelper';
6
- import { _, setupI18n, addNewMessages } from './i18n';
7
- import { VendorFilterPageTranslations } from './translations';
8
-
9
- export let endpoint:String = '';
10
- export let datasource:String = '';
11
- export let lang:String = ''; // Language
12
- export let session:String = ''; // Value for sessionID
13
- export let userid:String = '';
14
- export let clientstyling:String = '';
15
- export let clientstylingurl:String = '';
16
-
17
- let vendorsArray:Array<Object> = [];
18
- let mobileView:Boolean = false;
19
- let userAgent:String = window.navigator.userAgent;
20
- let applyFilters:boolean = false;
21
- let currentCategoryId:string = '';
22
-
23
- let categoryVendorFiltersCollection:Array<string> = JSON.parse(sessionStorage.getItem('vendorFiltersByCategory'));
24
-
25
- let provisionalVendorArray:any = [];
26
- let provisionalVendorObject:any = {};
27
- let isLoading:boolean = false;
28
- let filtersMarkedForClearance:boolean = false;
29
- let customStylingContainer:HTMLElement;
30
-
31
- if (provisionalVendorObject[currentCategoryId]) {
32
- provisionalVendorObject = {
33
- [currentCategoryId]: []
34
- }
35
- }
36
-
37
- let previousFilterSelection:any = [];
38
-
39
- setupI18n({ withLocale: 'en', translations: {}});
40
-
41
- Object.keys(VendorFilterPageTranslations).forEach((item) => {
42
- addNewMessages(item, VendorFilterPageTranslations[item]);
43
- });
44
-
45
- const messageHandler = (e:any) => {
46
- if (e.data) {
47
- switch (e.data.type) {
48
- case 'ShowFilterModal':
49
- // check if session holds any vendorFilters; if not, initialize the key with an empty value
50
- if (currentCategoryId) {
51
- categoryVendorFiltersCollection = JSON.parse(sessionStorage.getItem('vendorFiltersByCategory'));
52
-
53
- if (categoryVendorFiltersCollection) {
54
- provisionalVendorArray = categoryVendorFiltersCollection[currentCategoryId];
55
- }
56
- }
57
-
58
- if (!provisionalVendorArray) {
59
- let filters = sessionStorage.getItem("vendorFiltersByCategory");
60
-
61
- if (filters == null) {
62
- sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(provisionalVendorObject = {
63
- [currentCategoryId]: provisionalVendorArray
64
- }));
65
- } else {
66
- filters = JSON.parse(filters);
67
- filters[currentCategoryId] = provisionalVendorArray;
68
-
69
- sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(filters))
70
- }
71
- }
72
-
73
- getVendors(`${endpoint}/casino/vendors?filter=games(groups=${currentCategoryId})&datasource=${datasource}&platform=${getDevice(userAgent)}`);
74
-
75
- let selectedVendorsArray = provisionalVendorArray;
76
-
77
- if (selectedVendorsArray) {
78
- if (selectedVendorsArray.length) {
79
- vendorsArray.forEach((vendor:any) => {
80
- selectedVendorsArray.forEach((selected:any) => {
81
- if (vendor.id === selected) {
82
- vendor.isFilterSelected = true;
83
- }
84
- });
85
- })
86
- }
87
- }
88
-
89
- // populate values for vendor filter selection control
90
- previousFilterSelection = vendorsArray.reduce((arr:Array<any>, obj:any) => (obj.isFilterSelected && arr.push(obj.id), arr), []);
91
- provisionalVendorArray = previousFilterSelection;
92
- // initially, since there is no change in the vendor filter selection, the apply button is disabled
93
- applyFilters = false;
94
- break;
95
-
96
- case 'AvailableVendors':
97
- vendorsArray = e.data.venArray;
98
- provisionalVendorArray = vendorsArray.reduce((arr:Array<any>, obj:any) => (obj.isFilterSelected && arr.push(obj.id), arr), []);
99
- break;
100
-
101
- case 'UpdateSelectedVendorFilters':
102
- vendorsArray = e.data.venArray;
103
- if (vendorsArray) {
104
- provisionalVendorArray = vendorsArray.reduce((arr:Array<any>, obj:any) => (obj.isFilterSelected && arr.push(obj.id), arr), []);
105
- }
106
- break;
107
-
108
- case 'ClearVendorFilters':
109
- clearVendorFilter();
110
- window.postMessage({ type: "ApplyFilters" }, window.location.href);
111
- applyFilters = false;
112
- break;
113
-
114
- case 'FiltersModalClosed':
115
- vendorsArray.forEach((vendor:any) => {
116
- vendor.isFilterSelected = false;
117
- });
118
- window.postMessage({ type: "UpdateFilters", vendorsArray }, window.location.href);
119
- break;
120
-
121
- case 'CategoryVendors':
122
- currentCategoryId = e.data.categoryid;
123
-
124
- if (categoryVendorFiltersCollection) {
125
- if (currentCategoryId) {
126
- provisionalVendorArray = categoryVendorFiltersCollection[currentCategoryId];
127
- }
128
- }
129
-
130
- break;
131
-
132
- case 'ModalLoader':
133
- isLoading = false;
134
- break;
135
-
136
- default:
137
- // do nothing
138
- break;
139
- }
140
- }
141
- }
142
-
143
- const getVendors = (url:any) => {
144
- return new Promise((resolve, reject) => {
145
- fetch(url)
146
- .then((res:any) => res.json())
147
- .then((response:any) => {
148
- response = response.items;
149
-
150
- resolve(response.items);
151
-
152
- response.forEach((ven:any) => {
153
- let vendors = JSON.parse(sessionStorage.getItem('vendorFiltersByCategory'));
154
-
155
- if (!vendors) {
156
- vendors = {
157
- currentCategoryId: []
158
- }
159
- }
160
-
161
- if (currentCategoryId) {
162
- if (vendors[currentCategoryId]) {
163
- ven.isFilterSelected = (vendors[currentCategoryId].indexOf(ven.id) >= 0) ? true : false;
164
- }
165
- }
166
- });
167
-
168
- vendorsArray = response;
169
-
170
- window.postMessage({ type: "UpdateFilters", vendorsArray}, window.location.href);
171
- }).catch((err:any) => {
172
- console.error(err);
173
- reject(err);
174
- });
175
- });
176
- }
177
-
178
- const toggleVendorFilter = (vendor:Object) => {
179
- vendor.isFilterSelected = !vendor.isFilterSelected;
180
-
181
- if (vendor.isFilterSelected) {
182
- provisionalVendorArray.push(vendor.id);
183
- applyFilters = (!checkArrayEquality(provisionalVendorArray, previousFilterSelection)) ? true : false;
184
- } else {
185
- if (provisionalVendorArray.includes(vendor.id)) {
186
- provisionalVendorArray = provisionalVendorArray.filter(id => {
187
- return id !== vendor.id;
188
- });
189
- }
190
- applyFilters = (!provisionalVendorArray.length && checkArrayEquality(provisionalVendorArray, previousFilterSelection)) ? false : true;
191
- }
192
-
193
- window.postMessage({ type: "UpdateFilters", vendorsArray}, window.location.href);
194
- }
195
-
196
- // simple check for array euqlity, indifferent to array's elements order
197
- const checkArrayEquality = (arr1:Array<string>, arr2:Array<string>) => {
198
- if (arr1.length !== arr2.length) return false;
199
-
200
- const uniqueValues = new Set([...arr1, ...arr2]);
201
-
202
- for (const v of uniqueValues) {
203
- const arr1Count = arr1.filter(e => e === v).length;
204
- const arr2Count = arr2.filter(e => e === v).length;
205
-
206
- if (arr1Count !== arr2Count) return false;
207
- }
208
-
209
- return true;
210
- }
211
-
212
- const clearVendorFilter = () => {
213
- vendorsArray.forEach((ven) => {
214
- ven.isFilterSelected = false;
215
- });
216
- let filters = sessionStorage.getItem("vendorFiltersByCategory");
217
-
218
- window.postMessage({ type: "ClearFilters", vendorsArray}, window.location.href);
219
-
220
- filtersMarkedForClearance = true;
221
-
222
- // check if there are any differences between current and previous selections
223
- applyFilters = checkArrayEquality(provisionalVendorArray, previousFilterSelection);
224
- // clear current array
225
- provisionalVendorArray = [];
226
-
227
- if (filters !== null) {
228
- filters = JSON.parse(filters);
229
- filters[currentCategoryId] = provisionalVendorArray;
230
-
231
- sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(filters))
232
- }
233
- }
234
-
235
- const applyVendorFilter = () => {
236
- isLoading = true;
237
-
238
- let filters = sessionStorage.getItem("vendorFiltersByCategory");
239
-
240
- if (filters == null) {
241
- sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(provisionalVendorObject = {
242
- [currentCategoryId]: provisionalVendorArray
243
- }));
244
- } else {
245
- filters = JSON.parse(filters);
246
- filters[currentCategoryId] = provisionalVendorArray;
247
-
248
- sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(filters))
249
- }
250
-
251
- window.postMessage({ type: "ApplyFilters"}, window.location.href);
252
- }
253
-
254
- const setClientStyling = () => {
255
- let sheet = document.createElement('style');
256
-
257
- sheet.innerHTML = clientstyling;
258
- customStylingContainer.appendChild(sheet);
259
- }
260
-
261
- const setClientStylingURL = () => {
262
- let cssFile:HTMLElement = document.createElement('style');
263
-
264
- fetch(new URL(clientstylingurl))
265
- .then((res:any) => res.text())
266
- .then((data:any) => {
267
- cssFile.innerHTML = data
268
-
269
- if (customStylingContainer) {
270
- setTimeout(() => { customStylingContainer.appendChild(cssFile); }, 1);
271
- }
272
- });
273
- }
274
-
275
- onMount(() => {
276
- window.addEventListener('message', messageHandler, false);
277
-
278
- if (isMobile(userAgent)) {
279
- mobileView = true;
280
- }
281
-
282
- return () => {
283
- window.removeEventListener('message', messageHandler);
284
- }
285
- });
286
-
287
- $: clientstyling && setClientStyling();
288
- $: clientstylingurl && setClientStylingURL();
289
- </script>
290
-
291
- <div bind:this={customStylingContainer} part="CustomStylingContainer">
292
- {#if isLoading}
293
- <div class="lds-dual-ring" part="lds-dual-ring"></div>
294
- {:else}
295
- <div class="FilterModalContent {mobileView ? 'FilterModalMobileContent' : ''}" part="FilterModalContent {mobileView ? 'FilterModalMobileContent' : ''}">
296
- <section class="FilterHeaderSection" part="FilterHeaderSection">
297
- <div class="FilterHeaderDetails" part="FilterHeaderDetails">
298
- <h4 class="FilterHeaderTitle" part="FilterHeaderTitle">{$_('filters.filterModalTitle')}</h4>
299
- <h5 class="FilterHeaderSubtitle" part="FilterHeaderSubtitle">{$_('filters.filterModalSubtitle')}</h5>
300
- </div>
301
- </section>
302
- <section class="FilterContentSection" part="FilterContentSection">
303
- {#if vendorsArray}
304
- {#each vendorsArray as vendor}
305
- <div class="VendorBox {vendor.isFilterSelected ? 'VendorBoxSelected' : ''}" part="VendorBox {vendor.isFilterSelected ? 'VendorBoxSelected' : ''}" on:click="{() => toggleVendorFilter(vendor)}">
306
- <img class="VendorImage" part="VendorImage" src="{vendor.image}" alt="{vendor.name}" />
307
- {#if vendor.isFilterSelected}
308
- <div class="FilterIconContainer" part="FilterIconContainer">
309
- <div class="CheckMark" part="CheckMark"></div>
310
- </div>
311
- {/if}
312
- </div>
313
- {/each}
314
- {/if}
315
- </section>
316
- <section class="FilterFooterSection" part="FilterFooterSection">
317
- {#if provisionalVendorArray}
318
- {#if provisionalVendorArray.length}
319
- <div class="ClearFiltersButton" part="ClearFiltersButton" on:click="{() => clearVendorFilter()}">{$_('filters.filterClear')}</div>
320
- {/if}
321
- {/if}
322
- <div class="ApplyFiltersButton {!applyFilters ? 'ApplyFilterButtonDisabled' : ''}" part="ApplyFiltersButton {!applyFilters ? 'ApplyFilterButtonDisabled' : ''}" on:click="{() => applyVendorFilter()}">{$_('filters.filterApply')}</div>
323
- </section>
324
- </div>
325
- {/if}
326
- </div>
327
-
328
- <style lang="scss">
329
- :host {
330
- font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
331
- }
332
-
333
- .FilterModalContent {
334
- max-height: 80vh;
335
- display: flex;
336
- flex-direction: column;
337
- }
338
-
339
- .FilterHeaderSection {
340
- flex-grow: 0;
341
- }
342
-
343
- .FilterHeaderDetails {
344
- .FilterHeaderTitle {
345
- font-size: 34px;
346
- font-weight: 300;
347
- padding-bottom: 6px;
348
- margin-block-start: 0;
349
- margin-block-end: 0;
350
- }
351
- .FilterHeaderSubtitle {
352
- font-size: 18px;
353
- font-weight: 300;
354
- margin-block-start: 0;
355
- }
356
- }
357
- .FilterContentSection {
358
- display: inline-flex;
359
- flex-wrap: wrap;
360
- grid-gap: 25px;
361
- flex-grow: 1;
362
- overflow-y: auto;
363
- scrollbar-width: thin;
364
- scrollbar-color: var(--emfe-w-color-gray-300, #58586B) var(--emfe-w-color-gray-100, #E6E6E6);
365
- }
366
-
367
- .FilterContentSection::-webkit-scrollbar {
368
- width: 6px;
369
- }
370
-
371
- .FilterContentSection::-webkit-scrollbar-thumb {
372
- background: var(--emfe-w-color-gray-300, #58586B);
373
- }
374
-
375
- .FilterContentSection::-webkit-scrollbar-track {
376
- background: var(--emfe-w-color-gray-100, #E6E6E6);
377
- }
378
-
379
- .VendorBox {
380
- width: 230px;
381
- height: 125px;
382
- border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
383
- border-radius: 5px;
384
- position: relative;
385
- &.VendorBoxSelected {
386
- border: 1px solid var(--emfe-w-color-primary, #D0046C);
387
- }
388
- }
389
- .VendorImage {
390
- width: 100%;
391
- height: 100%;
392
- object-fit: contain;
393
- transition: all 150ms ease-in-out;
394
- }
395
- .FilterIconContainer {
396
- width: 25px;
397
- height: 25px;
398
- border-radius: 50%;
399
- display: flex;
400
- align-items: center;
401
- justify-content: center;
402
- position: absolute;
403
- bottom: 5px;
404
- right: 5px;
405
- background: var(--emfe-w-color-primary, #D0046C);
406
- .CheckMark {
407
- width: 5px;
408
- height: 12px;
409
- border-bottom: 2px solid var(--emfe-w-color-white, #FFFFFF);
410
- border-right: 2px solid var(--emfe-w-color-white, #FFFFFF);
411
- display: inline-block;
412
- position: relative;
413
- top: -2px;
414
- transform: rotate(45deg);
415
- }
416
- }
417
- .FilterFooterSection {
418
- display: flex;
419
- justify-content: center;
420
- grid-gap: 30px;
421
- margin-top: 60px;
422
- flex-grow: 0;
423
- .ClearFiltersButton, .ApplyFiltersButton {
424
- width: 180px;
425
- height: 50px;
426
- border: 1px solid var(--emfe-w-color-primary, #D0046C);
427
- border-radius: 5px;
428
- display: flex;
429
- align-items: center;
430
- justify-content: center;
431
- font-size: 16px;
432
- text-transform: uppercase;
433
- cursor: pointer;
434
- transition: border 150ms ease-in-out;
435
- &:hover {
436
- border: 1px solid var(--emfe-w-color-primary-100, #F1BED9);
437
- }
438
- }
439
- .ClearFiltersButton {
440
- background: var(--emfe-w-color-white, #FFFFFF);
441
- color: var(--emfe-w-color-primary, #D0046C);
442
- }
443
- .ApplyFiltersButton {
444
- background: var(--emfe-w-color-primary, #D0046C);
445
- color: var(--emfe-w-color-white, #FFFFFF);
446
- &.ApplyFilterButtonDisabled {
447
- background: var(--emfe-w-color-gray-100, #E6E6E6);
448
- border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
449
- pointer-events: none !important;
450
- // disable accidental text selection when trying to click on a disabled button
451
- -webkit-touch-callout: none; /* iOS Safari */
452
- -webkit-user-select: none; /* Safari */
453
- -khtml-user-select: none; /* Konqueror HTML */
454
- -moz-user-select: none; /* Old versions of Firefox */
455
- -ms-user-select: none; /* Internet Explorer/Edge */
456
- user-select: none; /* Non-prefixed version, currently
457
- supported by Chrome, Edge, Opera and Firefox */
458
- &:hover {
459
- cursor: not-allowed;
460
- border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
461
- }
462
- }
463
- }
464
- }
465
-
466
- .FilterModalMobileContent {
467
- .FilterHeaderSection {
468
- margin-top: 20px;
469
- text-align: center;
470
- color: var(--emfe-w-color-gray-300, #58586B);
471
- .FilterHeaderTitle {
472
- font-size: 18px;
473
- }
474
- .FilterHeaderSubtitle {
475
- font-size: 14px;
476
- }
477
- }
478
- .FilterContentSection {
479
- justify-content: center;
480
- grid-gap: 10px;
481
- .VendorBox {
482
- width: 150px;
483
- height: 80px;
484
- }
485
- }
486
- .FilterIconContainer {
487
- width: 12px;
488
- height: 12px;
489
- .CheckMark {
490
- width: 2px;
491
- height: 6px;
492
- border-bottom: 1px solid var(--emfe-w-color-white, #FFFFFF);
493
- border-right: 1px solid var(--emfe-w-color-white, #FFFFFF);
494
- top: 0px;
495
- left: 1px;
496
- }
497
- }
498
- .FilterFooterSection {
499
- margin: 30px auto 15px;
500
- grid-gap: 10px;
501
- width: 100%;
502
- .ClearFiltersButton, .ApplyFiltersButton {
503
- width: 100%;
504
- max-width: 180px;
505
- font-size: 12px;
506
- }
507
- }
508
- }
509
- .lds-dual-ring {
510
- display: block;
511
- width: 80px;
512
- height: 80px;
513
- margin: 0 auto
514
- }
515
- .lds-dual-ring:after {
516
- content: " ";
517
- display: block;
518
- width: 64px;
519
- height: 64px;
520
- margin: 8px;
521
- border-radius: 50%;
522
- border: 6px solid var(--emfe-w-color-primary, #D0046C);
523
- border-color: var(--emfe-w-color-primary, #D0046C) transparent var(--emfe-w-color-primary, #D0046C) transparent;
524
- animation: lds-dual-ring 1.2s linear infinite;
525
- }
526
- @keyframes lds-dual-ring {
527
- 0% {
528
- transform: rotate(0deg);
529
- }
530
- 100% {
531
- transform: rotate(360deg);
532
- }
533
- }
534
-
535
- </style>
1
+ <svelte:options tag={null} />
2
+
3
+ <script lang="ts">
4
+ import { onMount } from "svelte";
5
+ import { isMobile, getDevice } from 'rvhelper';
6
+ import { _, setupI18n, addNewMessages } from './i18n';
7
+ import { VendorFilterPageTranslations } from './translations';
8
+
9
+ export let endpoint:String = '';
10
+ export let datasource:String = '';
11
+ export let lang:String = ''; // Language
12
+ export let session:String = ''; // Value for sessionID
13
+ export let userid:String = '';
14
+ export let clientstyling:String = '';
15
+ export let clientstylingurl:String = '';
16
+
17
+ let vendorsArray:Array<Object> = [];
18
+ let mobileView:Boolean = false;
19
+ let userAgent:String = window.navigator.userAgent;
20
+ let applyFilters:boolean = false;
21
+ let currentCategoryId:string = '';
22
+
23
+ let categoryVendorFiltersCollection:Array<string> = JSON.parse(sessionStorage.getItem('vendorFiltersByCategory'));
24
+
25
+ let provisionalVendorArray:any = [];
26
+ let provisionalVendorObject:any = {};
27
+ let isLoading:boolean = false;
28
+ let filtersMarkedForClearance:boolean = false;
29
+ let customStylingContainer:HTMLElement;
30
+
31
+ if (provisionalVendorObject[currentCategoryId]) {
32
+ provisionalVendorObject = {
33
+ [currentCategoryId]: []
34
+ }
35
+ }
36
+
37
+ let previousFilterSelection:any = [];
38
+
39
+ setupI18n({ withLocale: 'en', translations: {}});
40
+
41
+ Object.keys(VendorFilterPageTranslations).forEach((item) => {
42
+ addNewMessages(item, VendorFilterPageTranslations[item]);
43
+ });
44
+
45
+ const messageHandler = (e:any) => {
46
+ if (e.data) {
47
+ switch (e.data.type) {
48
+ case 'ShowFilterModal':
49
+ // check if session holds any vendorFilters; if not, initialize the key with an empty value
50
+ if (currentCategoryId) {
51
+ categoryVendorFiltersCollection = JSON.parse(sessionStorage.getItem('vendorFiltersByCategory'));
52
+
53
+ if (categoryVendorFiltersCollection) {
54
+ provisionalVendorArray = categoryVendorFiltersCollection[currentCategoryId];
55
+ }
56
+ }
57
+
58
+ if (!provisionalVendorArray) {
59
+ let filters = sessionStorage.getItem("vendorFiltersByCategory");
60
+
61
+ if (filters == null) {
62
+ sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(provisionalVendorObject = {
63
+ [currentCategoryId]: provisionalVendorArray
64
+ }));
65
+ } else {
66
+ filters = JSON.parse(filters);
67
+ filters[currentCategoryId] = provisionalVendorArray;
68
+
69
+ sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(filters))
70
+ }
71
+ }
72
+
73
+ getVendors(`${endpoint}/casino/vendors?filter=games(groups=${currentCategoryId})&datasource=${datasource}&platform=${getDevice(userAgent)}`);
74
+
75
+ let selectedVendorsArray = provisionalVendorArray;
76
+
77
+ if (selectedVendorsArray) {
78
+ if (selectedVendorsArray.length) {
79
+ vendorsArray.forEach((vendor:any) => {
80
+ selectedVendorsArray.forEach((selected:any) => {
81
+ if (vendor.id === selected) {
82
+ vendor.isFilterSelected = true;
83
+ }
84
+ });
85
+ })
86
+ }
87
+ }
88
+
89
+ // populate values for vendor filter selection control
90
+ previousFilterSelection = vendorsArray.reduce((arr:Array<any>, obj:any) => (obj.isFilterSelected && arr.push(obj.id), arr), []);
91
+ provisionalVendorArray = previousFilterSelection;
92
+ // initially, since there is no change in the vendor filter selection, the apply button is disabled
93
+ applyFilters = false;
94
+ break;
95
+
96
+ case 'AvailableVendors':
97
+ vendorsArray = e.data.venArray;
98
+ provisionalVendorArray = vendorsArray.reduce((arr:Array<any>, obj:any) => (obj.isFilterSelected && arr.push(obj.id), arr), []);
99
+ break;
100
+
101
+ case 'UpdateSelectedVendorFilters':
102
+ vendorsArray = e.data.venArray;
103
+ if (vendorsArray) {
104
+ provisionalVendorArray = vendorsArray.reduce((arr:Array<any>, obj:any) => (obj.isFilterSelected && arr.push(obj.id), arr), []);
105
+ }
106
+ break;
107
+
108
+ case 'ClearVendorFilters':
109
+ clearVendorFilter();
110
+ window.postMessage({ type: "ApplyFilters" }, window.location.href);
111
+ applyFilters = false;
112
+ break;
113
+
114
+ case 'FiltersModalClosed':
115
+ vendorsArray.forEach((vendor:any) => {
116
+ vendor.isFilterSelected = false;
117
+ });
118
+ window.postMessage({ type: "UpdateFilters", vendorsArray }, window.location.href);
119
+ break;
120
+
121
+ case 'CategoryVendors':
122
+ currentCategoryId = e.data.categoryid;
123
+
124
+ if (categoryVendorFiltersCollection) {
125
+ if (currentCategoryId) {
126
+ provisionalVendorArray = categoryVendorFiltersCollection[currentCategoryId];
127
+ }
128
+ }
129
+
130
+ break;
131
+
132
+ case 'ModalLoader':
133
+ isLoading = false;
134
+ break;
135
+
136
+ default:
137
+ // do nothing
138
+ break;
139
+ }
140
+ }
141
+ }
142
+
143
+ const getVendors = (url:any) => {
144
+ return new Promise((resolve, reject) => {
145
+ fetch(url)
146
+ .then((res:any) => res.json())
147
+ .then((response:any) => {
148
+ response = response.items;
149
+
150
+ resolve(response.items);
151
+
152
+ response.forEach((ven:any) => {
153
+ let vendors = JSON.parse(sessionStorage.getItem('vendorFiltersByCategory'));
154
+
155
+ if (!vendors) {
156
+ vendors = {
157
+ currentCategoryId: []
158
+ }
159
+ }
160
+
161
+ if (currentCategoryId) {
162
+ if (vendors[currentCategoryId]) {
163
+ ven.isFilterSelected = (vendors[currentCategoryId].indexOf(ven.id) >= 0) ? true : false;
164
+ }
165
+ }
166
+ });
167
+
168
+ vendorsArray = response;
169
+
170
+ window.postMessage({ type: "UpdateFilters", vendorsArray}, window.location.href);
171
+ }).catch((err:any) => {
172
+ console.error(err);
173
+ reject(err);
174
+ });
175
+ });
176
+ }
177
+
178
+ const toggleVendorFilter = (vendor:Object) => {
179
+ vendor.isFilterSelected = !vendor.isFilterSelected;
180
+
181
+ if (vendor.isFilterSelected) {
182
+ provisionalVendorArray.push(vendor.id);
183
+ applyFilters = (!checkArrayEquality(provisionalVendorArray, previousFilterSelection)) ? true : false;
184
+ } else {
185
+ if (provisionalVendorArray.includes(vendor.id)) {
186
+ provisionalVendorArray = provisionalVendorArray.filter(id => {
187
+ return id !== vendor.id;
188
+ });
189
+ }
190
+ applyFilters = (!provisionalVendorArray.length && checkArrayEquality(provisionalVendorArray, previousFilterSelection)) ? false : true;
191
+ }
192
+
193
+ window.postMessage({ type: "UpdateFilters", vendorsArray}, window.location.href);
194
+ }
195
+
196
+ // simple check for array euqlity, indifferent to array's elements order
197
+ const checkArrayEquality = (arr1:Array<string>, arr2:Array<string>) => {
198
+ if (arr1.length !== arr2.length) return false;
199
+
200
+ const uniqueValues = new Set([...arr1, ...arr2]);
201
+
202
+ for (const v of uniqueValues) {
203
+ const arr1Count = arr1.filter(e => e === v).length;
204
+ const arr2Count = arr2.filter(e => e === v).length;
205
+
206
+ if (arr1Count !== arr2Count) return false;
207
+ }
208
+
209
+ return true;
210
+ }
211
+
212
+ const clearVendorFilter = () => {
213
+ vendorsArray.forEach((ven) => {
214
+ ven.isFilterSelected = false;
215
+ });
216
+ let filters = sessionStorage.getItem("vendorFiltersByCategory");
217
+
218
+ window.postMessage({ type: "ClearFilters", vendorsArray}, window.location.href);
219
+
220
+ filtersMarkedForClearance = true;
221
+
222
+ // check if there are any differences between current and previous selections
223
+ applyFilters = checkArrayEquality(provisionalVendorArray, previousFilterSelection);
224
+ // clear current array
225
+ provisionalVendorArray = [];
226
+
227
+ if (filters !== null) {
228
+ filters = JSON.parse(filters);
229
+ filters[currentCategoryId] = provisionalVendorArray;
230
+
231
+ sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(filters))
232
+ }
233
+ }
234
+
235
+ const applyVendorFilter = () => {
236
+ isLoading = true;
237
+
238
+ let filters = sessionStorage.getItem("vendorFiltersByCategory");
239
+
240
+ if (filters == null) {
241
+ sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(provisionalVendorObject = {
242
+ [currentCategoryId]: provisionalVendorArray
243
+ }));
244
+ } else {
245
+ filters = JSON.parse(filters);
246
+ filters[currentCategoryId] = provisionalVendorArray;
247
+
248
+ sessionStorage.setItem("vendorFiltersByCategory", JSON.stringify(filters))
249
+ }
250
+
251
+ window.postMessage({ type: "ApplyFilters"}, window.location.href);
252
+ }
253
+
254
+ const setClientStyling = () => {
255
+ let sheet = document.createElement('style');
256
+
257
+ sheet.innerHTML = clientstyling;
258
+ customStylingContainer.appendChild(sheet);
259
+ }
260
+
261
+ const setClientStylingURL = () => {
262
+ let cssFile:HTMLElement = document.createElement('style');
263
+
264
+ fetch(new URL(clientstylingurl))
265
+ .then((res:any) => res.text())
266
+ .then((data:any) => {
267
+ cssFile.innerHTML = data
268
+
269
+ if (customStylingContainer) {
270
+ setTimeout(() => { customStylingContainer.appendChild(cssFile); }, 1);
271
+ }
272
+ });
273
+ }
274
+
275
+ onMount(() => {
276
+ window.addEventListener('message', messageHandler, false);
277
+
278
+ if (isMobile(userAgent)) {
279
+ mobileView = true;
280
+ }
281
+
282
+ return () => {
283
+ window.removeEventListener('message', messageHandler);
284
+ }
285
+ });
286
+
287
+ $: clientstyling && setClientStyling();
288
+ $: clientstylingurl && setClientStylingURL();
289
+ </script>
290
+
291
+ <div bind:this={customStylingContainer} part="CustomStylingContainer">
292
+ {#if isLoading}
293
+ <div class="lds-dual-ring" part="lds-dual-ring"></div>
294
+ {:else}
295
+ <div class="FilterModalContent {mobileView ? 'FilterModalMobileContent' : ''}" part="FilterModalContent {mobileView ? 'FilterModalMobileContent' : ''}">
296
+ <section class="FilterHeaderSection" part="FilterHeaderSection">
297
+ <div class="FilterHeaderDetails" part="FilterHeaderDetails">
298
+ <h4 class="FilterHeaderTitle" part="FilterHeaderTitle">{$_('filters.filterModalTitle')}</h4>
299
+ <h5 class="FilterHeaderSubtitle" part="FilterHeaderSubtitle">{$_('filters.filterModalSubtitle')}</h5>
300
+ </div>
301
+ </section>
302
+ <section class="FilterContentSection" part="FilterContentSection">
303
+ {#if vendorsArray}
304
+ {#each vendorsArray as vendor}
305
+ <div class="VendorBox {vendor.isFilterSelected ? 'VendorBoxSelected' : ''}" part="VendorBox {vendor.isFilterSelected ? 'VendorBoxSelected' : ''}" on:click="{() => toggleVendorFilter(vendor)}">
306
+ <img class="VendorImage" part="VendorImage" src="{vendor.image}" alt="{vendor.name}" />
307
+ {#if vendor.isFilterSelected}
308
+ <div class="FilterIconContainer" part="FilterIconContainer">
309
+ <div class="CheckMark" part="CheckMark"></div>
310
+ </div>
311
+ {/if}
312
+ </div>
313
+ {/each}
314
+ {/if}
315
+ </section>
316
+ <section class="FilterFooterSection" part="FilterFooterSection">
317
+ {#if provisionalVendorArray}
318
+ {#if provisionalVendorArray.length}
319
+ <div class="ClearFiltersButton" part="ClearFiltersButton" on:click="{() => clearVendorFilter()}">{$_('filters.filterClear')}</div>
320
+ {/if}
321
+ {/if}
322
+ <div class="ApplyFiltersButton {!applyFilters ? 'ApplyFilterButtonDisabled' : ''}" part="ApplyFiltersButton {!applyFilters ? 'ApplyFilterButtonDisabled' : ''}" on:click="{() => applyVendorFilter()}">{$_('filters.filterApply')}</div>
323
+ </section>
324
+ </div>
325
+ {/if}
326
+ </div>
327
+
328
+ <style lang="scss">
329
+ :host {
330
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
331
+ }
332
+
333
+ .FilterModalContent {
334
+ max-height: 80vh;
335
+ display: flex;
336
+ flex-direction: column;
337
+ }
338
+
339
+ .FilterHeaderSection {
340
+ flex-grow: 0;
341
+ }
342
+
343
+ .FilterHeaderDetails {
344
+ .FilterHeaderTitle {
345
+ font-size: 34px;
346
+ font-weight: 300;
347
+ padding-bottom: 6px;
348
+ margin-block-start: 0;
349
+ margin-block-end: 0;
350
+ }
351
+ .FilterHeaderSubtitle {
352
+ font-size: 18px;
353
+ font-weight: 300;
354
+ margin-block-start: 0;
355
+ }
356
+ }
357
+ .FilterContentSection {
358
+ display: inline-flex;
359
+ flex-wrap: wrap;
360
+ grid-gap: 25px;
361
+ flex-grow: 1;
362
+ overflow-y: auto;
363
+ scrollbar-width: thin;
364
+ scrollbar-color: var(--emfe-w-color-gray-300, #58586B) var(--emfe-w-color-gray-100, #E6E6E6);
365
+ }
366
+
367
+ .FilterContentSection::-webkit-scrollbar {
368
+ width: 6px;
369
+ }
370
+
371
+ .FilterContentSection::-webkit-scrollbar-thumb {
372
+ background: var(--emfe-w-color-gray-300, #58586B);
373
+ }
374
+
375
+ .FilterContentSection::-webkit-scrollbar-track {
376
+ background: var(--emfe-w-color-gray-100, #E6E6E6);
377
+ }
378
+
379
+ .VendorBox {
380
+ width: 230px;
381
+ height: 125px;
382
+ border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
383
+ border-radius: 5px;
384
+ position: relative;
385
+ &.VendorBoxSelected {
386
+ border: 1px solid var(--emfe-w-color-primary, #D0046C);
387
+ }
388
+ }
389
+ .VendorImage {
390
+ width: 100%;
391
+ height: 100%;
392
+ object-fit: contain;
393
+ transition: all 150ms ease-in-out;
394
+ }
395
+ .FilterIconContainer {
396
+ width: 25px;
397
+ height: 25px;
398
+ border-radius: 50%;
399
+ display: flex;
400
+ align-items: center;
401
+ justify-content: center;
402
+ position: absolute;
403
+ bottom: 5px;
404
+ right: 5px;
405
+ background: var(--emfe-w-color-primary, #D0046C);
406
+ .CheckMark {
407
+ width: 5px;
408
+ height: 12px;
409
+ border-bottom: 2px solid var(--emfe-w-color-white, #FFFFFF);
410
+ border-right: 2px solid var(--emfe-w-color-white, #FFFFFF);
411
+ display: inline-block;
412
+ position: relative;
413
+ top: -2px;
414
+ transform: rotate(45deg);
415
+ }
416
+ }
417
+ .FilterFooterSection {
418
+ display: flex;
419
+ justify-content: center;
420
+ grid-gap: 30px;
421
+ margin-top: 60px;
422
+ flex-grow: 0;
423
+ .ClearFiltersButton, .ApplyFiltersButton {
424
+ width: 180px;
425
+ height: 50px;
426
+ border: 1px solid var(--emfe-w-color-primary, #D0046C);
427
+ border-radius: 5px;
428
+ display: flex;
429
+ align-items: center;
430
+ justify-content: center;
431
+ font-size: 16px;
432
+ text-transform: uppercase;
433
+ cursor: pointer;
434
+ transition: border 150ms ease-in-out;
435
+ &:hover {
436
+ border: 1px solid var(--emfe-w-color-primary-100, #F1BED9);
437
+ }
438
+ }
439
+ .ClearFiltersButton {
440
+ background: var(--emfe-w-color-white, #FFFFFF);
441
+ color: var(--emfe-w-color-primary, #D0046C);
442
+ }
443
+ .ApplyFiltersButton {
444
+ background: var(--emfe-w-color-primary, #D0046C);
445
+ color: var(--emfe-w-color-white, #FFFFFF);
446
+ &.ApplyFilterButtonDisabled {
447
+ background: var(--emfe-w-color-gray-100, #E6E6E6);
448
+ border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
449
+ pointer-events: none !important;
450
+ // disable accidental text selection when trying to click on a disabled button
451
+ -webkit-touch-callout: none; /* iOS Safari */
452
+ -webkit-user-select: none; /* Safari */
453
+ -khtml-user-select: none; /* Konqueror HTML */
454
+ -moz-user-select: none; /* Old versions of Firefox */
455
+ -ms-user-select: none; /* Internet Explorer/Edge */
456
+ user-select: none; /* Non-prefixed version, currently
457
+ supported by Chrome, Edge, Opera and Firefox */
458
+ &:hover {
459
+ cursor: not-allowed;
460
+ border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
461
+ }
462
+ }
463
+ }
464
+ }
465
+
466
+ .FilterModalMobileContent {
467
+ .FilterHeaderSection {
468
+ margin-top: 20px;
469
+ text-align: center;
470
+ color: var(--emfe-w-color-gray-300, #58586B);
471
+ .FilterHeaderTitle {
472
+ font-size: 18px;
473
+ }
474
+ .FilterHeaderSubtitle {
475
+ font-size: 14px;
476
+ }
477
+ }
478
+ .FilterContentSection {
479
+ justify-content: center;
480
+ grid-gap: 10px;
481
+ .VendorBox {
482
+ width: 150px;
483
+ height: 80px;
484
+ }
485
+ }
486
+ .FilterIconContainer {
487
+ width: 12px;
488
+ height: 12px;
489
+ .CheckMark {
490
+ width: 2px;
491
+ height: 6px;
492
+ border-bottom: 1px solid var(--emfe-w-color-white, #FFFFFF);
493
+ border-right: 1px solid var(--emfe-w-color-white, #FFFFFF);
494
+ top: 0px;
495
+ left: 1px;
496
+ }
497
+ }
498
+ .FilterFooterSection {
499
+ margin: 30px auto 15px;
500
+ grid-gap: 10px;
501
+ width: 100%;
502
+ .ClearFiltersButton, .ApplyFiltersButton {
503
+ width: 100%;
504
+ max-width: 180px;
505
+ font-size: 12px;
506
+ }
507
+ }
508
+ }
509
+ .lds-dual-ring {
510
+ display: block;
511
+ width: 80px;
512
+ height: 80px;
513
+ margin: 0 auto
514
+ }
515
+ .lds-dual-ring:after {
516
+ content: " ";
517
+ display: block;
518
+ width: 64px;
519
+ height: 64px;
520
+ margin: 8px;
521
+ border-radius: 50%;
522
+ border: 6px solid var(--emfe-w-color-primary, #D0046C);
523
+ border-color: var(--emfe-w-color-primary, #D0046C) transparent var(--emfe-w-color-primary, #D0046C) transparent;
524
+ animation: lds-dual-ring 1.2s linear infinite;
525
+ }
526
+ @keyframes lds-dual-ring {
527
+ 0% {
528
+ transform: rotate(0deg);
529
+ }
530
+ 100% {
531
+ transform: rotate(360deg);
532
+ }
533
+ }
534
+
535
+ </style>