@everymatrix/casino-tournaments-page-controller 0.0.367 → 0.0.368

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,817 +1,817 @@
1
- <svelte:options tag={null}/>
2
-
3
- <script lang="ts">
4
- import { onMount } from 'svelte';
5
- import moment from 'moment';
6
- import { isMobile, getDevice, checkSession } from 'rvhelper';
7
- import { _, addNewMessages, date, setLocale, setupI18n } from './i18n';
8
- import { TournamentsPageTranslations } from './translations';
9
- import { EventSourcePolyfill } from 'event-source-polyfill';
10
-
11
- import gameCasinoSvg from './images/game-casino.svg';
12
- import gameSportsSvg from './images/game-sports.svg'
13
-
14
- import '@everymatrix/casino-tournaments-details';
15
- import '@everymatrix/casino-tournaments-thumbnail-controller';
16
- import '@everymatrix/casino-tournaments-table';
17
- import '@everymatrix/casino-tournaments-tab';
18
- import '@everymatrix/casino-tournaments-thumbnail-rule';
19
- import '@everymatrix/casino-tournaments-rank';
20
-
21
- export let session: string = '';
22
- export let userid: string = '';
23
- export let tourid: string = '';
24
- export let endpoint: string = '';
25
- export let showleaderboard: string = '';
26
- export let cmsendpoint: string = '';
27
- export let lang: string = '';
28
- export let navigationbackbutton: string = 'Default';
29
- export let currency: string = 'EUR';
30
- export let tablelimit: string = '30';
31
- export let namemask: string = '';
32
- export let showunqualifiedplayer: string = 'true'
33
- export let mobiletablelimit:string = '15';
34
- export let updatetableintime:string = 'true';
35
- export let viewmode:string = '';
36
- export let minscore:string = '';
37
-
38
- export let leaderboardoffset:string = '0';
39
- export let leaderboardlimit:string = '15';
40
- export let keepbrowsercontext:string = 'false';
41
- // Variables of topics for communication
42
- let sessionTopic;
43
-
44
- let isLoggedIn: boolean = false;
45
- let sessionID: string = '';
46
- let playerID: string = '';
47
- let isLoading: boolean = true;
48
- let tournamentDescription: Array<any> = [];
49
- let tournamentProducts:any;
50
-
51
- let tournamentDetails: any = undefined;
52
- let tournamentTableData: any = undefined;
53
-
54
- let userAgent = window.navigator.userAgent;
55
-
56
- let showTable: boolean = false;
57
- let firstRowData: any = {};
58
- let firstRowAvailable: boolean = false;
59
-
60
- let tableUpdateEventSource: any;
61
- let tournamentUpdateEventSource:EventSourcePolyfill;
62
-
63
- let currentUserData:any = {};
64
- let currentUserInPage:Boolean = false;
65
- let activeTab = 'leaderboard';
66
- let overallRank:number;
67
- let latestRank:number;
68
- let isMiniMode:boolean;
69
- let shownStatus:any = '';
70
-
71
- setupI18n({ withLocale: 'en', translations: {}});
72
-
73
- Object.keys(TournamentsPageTranslations).forEach((item: any) => {
74
- addNewMessages(item, TournamentsPageTranslations[item]);
75
- });
76
-
77
- // @TODO this must be configurable
78
- const tableColumns = ['Rank', 'Player', 'Points','Prize'];
79
- // data for current user
80
- const transFormCurrentUserData = (item:any) => {
81
- let userData = {
82
- Rank: showunqualifiedplayer == "false" ? item.rankWithoutUnqualified : item.rank,
83
- Player: item.shortName,
84
- Points: item.score,
85
- Prize: item.prizeName,
86
- Unqualified: item.unqualified,
87
- BetCount: item.betCount,
88
- userID: item.userID
89
- };
90
- return userData;
91
- }
92
-
93
- const transFormCurrentUserDataAtFistRow = (item: any) => ({
94
- ...transFormCurrentUserData(item),
95
- ...(item.unqualified === true ? { Rank: item.rank } : {})
96
- })
97
-
98
- // @TODO data type
99
- const transformTableData = (data:any) => {
100
-
101
- currentUserInPage = false
102
-
103
- let tableData:any = [];
104
-
105
- if (data && data.length > 0) {
106
- data.forEach((item:any) => {
107
- let transformedItem = transFormCurrentUserData(item)
108
- if(item.userID == playerID){
109
- currentUserData = transformedItem;
110
- currentUserInPage = true;
111
- }
112
- tableData.push(transformedItem);
113
- });
114
- }
115
-
116
- return tableData;
117
- },
118
- tournamentUpdateMessageHandler= (message:any) =>{
119
- if(!message.data){
120
- return;
121
- }
122
- try{
123
- let messagDataAsJson = JSON.parse(message.data);
124
- if(messagDataAsJson.messageType == 'TournamentUpdate'){
125
- window.postMessage({type: 'UpdateTournamentView', tournamentData: messagDataAsJson.item}, window.location.href);
126
- tournamentDetails = messagDataAsJson.item;
127
- transformTournamentData(messagDataAsJson.item);
128
- matchStatus();
129
- }
130
- }catch (e){
131
- console.error(e);
132
- }
133
- },
134
- startupTournamentUpdateListener = (tournamentID: string, searchParams:any)=>{
135
- let endpointURL:string = `${endpoint}/tournaments/updates?filter=id=${tournamentID}&${searchParams.toString()}&XSessionId=${session}`;
136
- if(!EventSource){
137
- tournamentUpdateEventSource = new EventSourcePolyfill(endpointURL,{headers: {'accept': 'text/event-stream'}});
138
- }else{
139
- tournamentUpdateEventSource = new EventSource(endpointURL);
140
- }
141
- if (!typeof (tournamentUpdateEventSource) != 'undefined'){
142
- tournamentUpdateEventSource.addEventListener('message', tournamentUpdateMessageHandler);
143
- }
144
- },
145
- tableUpdateMessageHandler = (message:any)=>{
146
- if(!message.data){
147
- return;
148
- }
149
- try{
150
- let messageData:any = message.data;
151
- let updateTableData:any = JSON.parse(messageData);
152
- if(!updateTableData || !updateTableData.items){
153
- return;
154
- }
155
- let newTableData: Array<LeaderboardRow> = transformTableData(updateTableData.items);
156
- window.postMessage({ type: 'CasinoTableData', tableData: newTableData }, window.location.href);
157
- currentUserInPage = newTableData.filter((item)=>{
158
- return item.userID = playerID;
159
- }).length > 0;
160
- if(updateTableData.item){
161
- firstRowAvailable = true;
162
- firstRowData = transFormCurrentUserDataAtFistRow(updateTableData.item);
163
- if(firstRowData){
164
- window.postMessage({ type: 'CasinoTableFirstRowData', tableData: firstRowData }, window.location.href);
165
- }
166
- }
167
-
168
- let newUserRank = currentUserInPage ? currentUserData.Rank : firstRowData.Rank;
169
- if(newUserRank != latestRank || overallRank != updateTableData.items.length){
170
- overallRank = updateTableData.items.length;//new player joined and spined
171
- window.postMessage({type: `TournamentRankInfo_${tourid}`, rankInfo:{
172
- rank: newUserRank,
173
- overallRank: overallRank,
174
- prize: currentUserInPage ? (currentUserData.Prize || '-') : (firstRowData.Prize || '-')
175
- }});
176
- latestRank = newUserRank;
177
- }
178
-
179
- if(currentUserInPage){
180
- window.postMessage({ type: 'CasinoTableCurrentUserData', tableData: currentUserData }, window.location.href);
181
- }
182
- }catch(err){
183
- console.error(err);
184
- }
185
- },
186
- startupTableDataChangeListener = (tournamentID: String, searchParams: any) => {
187
- let endpointURL: String = `${endpoint}/tournaments/${tournamentID}/leaderboard/updates?HeartBeat=false&XSessionId=${session}&${searchParams.toString()}`;
188
- if(tableUpdateEventSource){
189
- return;
190
- }
191
- if(!EventSource){
192
- tableUpdateEventSource = new EventSourcePolyfill(endpointURL,{headers: {'accept': 'text/event-stream'}});
193
- }else{
194
- tableUpdateEventSource = new EventSource(endpointURL);
195
- }
196
- if (typeof (tableUpdateEventSource) != "undefined") {
197
- tableUpdateEventSource.addEventListener('open', tableUpdateMessageHandler);
198
- tableUpdateEventSource.addEventListener('message', tableUpdateMessageHandler);
199
- tableUpdateEventSource.addEventListener('error', tableUpdateMessageHandler);
200
- }
201
- },
202
- transformTournamentData = (data:any)=>{
203
- let productInfo={};
204
- if(data.wallet){
205
- let wallet = data.wallet;
206
- if(wallet.casino){
207
- productInfo['casino'] = {
208
- name: 'Casino',
209
- minbet: wallet.casino.minStake && wallet.casino.minStake.amount ? wallet.casino.minStake.amount.EUR : $_('tournamentsPage.unlimited'),
210
- maxbet: wallet.casino.maxStake && wallet.casino.maxStake.amount ? wallet.casino.maxStake.amount.EUR : $_('tournamentsPage.unlimited')
211
- }
212
- }
213
- if(wallet.sports){
214
- productInfo['sports'] = {
215
- name: 'Sports',
216
- minbet: wallet.sports.minStake && wallet.sports.minStake.amount ? wallet.sports.minStake.amount.EUR : $_('tournamentsPage.unlimited'),
217
- maxbet: wallet.sports.maxStake && wallet.sports.maxStake.amount ? wallet.sports.maxStake.amount.EUR : $_('tournamentsPage.unlimited')
218
- }
219
- }
220
- tournamentProducts = productInfo;
221
- }
222
- }
223
-
224
- const getData = (endpointURL: String, tourID: String) => {
225
- let url = new URL(endpointURL + `/tournaments/${tourID}`);
226
- let reqHeaders = new Headers({'X-SessionId': session});
227
-
228
- url.searchParams.append('expand', 'games');
229
- url.searchParams.append('language', lang);
230
- url.searchParams.append('platform', getDevice(userAgent));
231
-
232
- let requestOptions = {
233
- method: 'GET',
234
- headers: reqHeaders,
235
- };
236
-
237
- fetch(url.href, requestOptions)
238
- .then((res: any) => res.json())
239
- .then((res: any) => {
240
- tournamentDetails = res.item;
241
- transformTournamentData(tournamentDetails);
242
- startupTournamentUpdateListener(tourid, url.searchParams);
243
- });
244
- }
245
-
246
- const getTableData = (endpointURL: String, tourID: String) => {
247
- let url = new URL(endpointURL + `/tournaments/${tourID}/leaderboard`);
248
- let reqHeaders = new Headers();
249
-
250
- url.searchParams.append('language', lang);
251
-
252
- let tableFilter = `includeUnqualifiedPlayer=${showunqualifiedplayer}`;
253
- tableFilter = namemask ? `${tableFilter},shortNameMask=${namemask}` : tableFilter;
254
- tableFilter = minscore ? `${tableFilter},minscore=${minscore}` : tableFilter;
255
-
256
- url.searchParams.append('filter', tableFilter);
257
-
258
- if (session) {
259
- let limit = isMobile(userAgent) == true? mobiletablelimit : tablelimit;
260
- url.searchParams.append('pagination', `offset=0,limit=${limit}`);
261
- reqHeaders.append('X-SessionId', session);
262
- }
263
- url.searchParams.append('platform', getDevice(userAgent));
264
-
265
- let requestOptions = {
266
- method: 'GET',
267
- headers: reqHeaders,
268
- };
269
-
270
- fetch(url, requestOptions)
271
- .then((res: any) => res.json())
272
- .then((res: any) => {
273
- tournamentTableData = transformTableData(res.items);
274
- if(res.item && !currentUserInPage){
275
- firstRowAvailable = true;
276
- firstRowData = transFormCurrentUserDataAtFistRow(res.item);
277
- }
278
- showTable = true;
279
- latestRank = currentUserInPage ? currentUserData.Rank : firstRowData.Rank
280
- overallRank = res.total;
281
-
282
- // @TODO data is not iterable error fix
283
- window.postMessage({
284
- type: 'CasinoTableData',
285
- tableData: tournamentTableData
286
- }, window.location.href);
287
- window.postMessage({type: 'CasinoTableColumns', tableColumns}, window.location.href);
288
- if (firstRowAvailable) {
289
- window.postMessage({type: 'CasinoTableFirstRowData', tableData: firstRowData}, window.location.href);
290
- }
291
- if(updatetableintime === 'true'){
292
- startupTableDataChangeListener(tourID, url.searchParams);
293
- }
294
- if (currentUserInPage){
295
- window.postMessage({ type: 'CasinoTableCurrentUserData', tableData: currentUserData }, window.location.href);
296
- }
297
- });
298
- }
299
-
300
- const messageHandler = (e: any) => {
301
- if (e.data && e.data.type == 'UserSessionID') {
302
- isLoggedIn = true;
303
- sessionID = e.data.session;
304
- }
305
-
306
- if (e.data && e.data.type == 'PlayerID') {
307
- playerID = e.data.playerID;
308
- }
309
- if(e.data && e.data.type == 'TournamentsTabSwitch'){
310
- activeTab = e.data.tab;
311
- }
312
- }
313
-
314
- const matchStatus = () => {
315
- if (tournamentDetails.state == 'Unstarted') {
316
- shownStatus = $_('tournamentsPage.scheduled');
317
- }
318
-
319
- if (tournamentDetails.state == 'Running') {
320
- shownStatus = $_('tournamentsPage.ongoing');
321
- }
322
-
323
- if (tournamentDetails.state == 'Closed' || tournamentDetails.state == 'Closing') {
324
- shownStatus = $_('tournamentsPage.finished');
325
- }
326
- }
327
-
328
- const goBack = () => {
329
- // this function handles the back navigation making use of the prop: navigationbackbutton. If it has the
330
- // event value, it will emit the 'RedirectBack' event which will enable the client to handle the routing;
331
- // else, if it has the 'Default' value, it will do a window.history.back()
332
- if (navigationbackbutton == 'Event') {
333
- window.postMessage({type: 'RedirectBack'}, window.location.href);
334
- } else if (navigationbackbutton == 'Default') {
335
- window.history.back();
336
- }
337
- }
338
- const closeThumbnail = () =>{
339
- window.postMessage({ type: 'OnCloseThumbnail' }, window.location.href);
340
- }
341
- const gotoFromTournamentsPage = (pageType: string) =>{
342
- window.postMessage({ type: 'GotoFromTournamentsPage', pageType }, window.location.href);
343
- }
344
-
345
- const setSession = () => {
346
- if (session.length > 0 && session != 'false') {
347
- sessionID = session;
348
- playerID = userid;
349
- isLoggedIn = true;
350
- } else {
351
- isLoggedIn = false;
352
- }
353
-
354
- isLoading = false;
355
- }
356
- const setActiveLanguage = ():void => {
357
- setLocale(lang);
358
- initTabTitle()
359
- }
360
- const initialLoad = () => {
361
- setLocale(lang);
362
- getData(endpoint, tourid);
363
- getTableData(endpoint, tourid);
364
- }
365
-
366
- const getDataFromCMS = () => {
367
- fetch(`${cmsendpoint}/${tourid}`)
368
- .then((res: any) => res.json())
369
- .then((data: any) => {
370
- if (data && data.details) {
371
- tournamentDescription = data.details;
372
- }
373
- });
374
- }
375
- const initTabTitle= () =>{
376
- window.postMessage({type: 'TournamentsTabLocaleTextUpdate','state': 'leaderboard', 'text': $_('tournamentsPage.leaderBoard')}, window.location.href)
377
- window.postMessage({type: 'TournamentsTabLocaleTextUpdate','state': 'rules', 'text': $_('tournamentsPage.rules')}, window.location.href)
378
- window.postMessage({type: 'TournamentsTabLocaleTextUpdate','state': 'games', 'text': $_('tournamentsPage.games')}, window.location.href)
379
- }
380
-
381
- onMount(() => {
382
- window.addEventListener('message', messageHandler, false);
383
- return () => {
384
- window.removeEventListener('message', messageHandler);
385
- if(tableUpdateEventSource){
386
- tableUpdateEventSource.removeEventListener('open', tableUpdateMessageHandler);
387
- tableUpdateEventSource.removeEventListener('message', tableUpdateMessageHandler);
388
- tableUpdateEventSource.removeEventListener('error', tableUpdateMessageHandler);
389
- }
390
- if(tournamentUpdateEventSource){
391
- tournamentUpdateEventSource.removeEventListener('message', tournamentUpdateMessageHandler);
392
- }
393
- }
394
- });
395
-
396
- $: session && userid && setSession();
397
- $: lang && setActiveLanguage();
398
- $: initialParameters = tourid && endpoint && session && lang;
399
- $: initialParameters && initialLoad();
400
- $: cmsendpoint && tourid && getDataFromCMS();
401
- $: isMiniMode = (viewmode != 'desktop') && isMobile(userAgent); // forward this page from tournamentslider
402
- </script>
403
-
404
- {#if isLoading}
405
- <p class="LoadingMessage" part="LoadingMessage">
406
- {$_('tournamentsPage.loading')}
407
- </p>
408
- {/if}
409
- {#if !isMiniMode}
410
- <div class="TournamentsPage" part="TournamentsPage">
411
- <div class="TournamentsSectionWrapper" part="TournamentsSectionWrapper">
412
-
413
- <div class="TopButtons" part="TopButtons">
414
- <div class="BackButton" part="BackButton" on:click={() => goBack()}>
415
- <svg fill="none" stroke="currentColor" width="24" height="24" viewBox="0 0 24 24"
416
- xmlns="http://www.w3.org/2000/svg">
417
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
418
- </svg>
419
- <p>{$_('tournamentsPage.back')}</p>
420
- </div>
421
- <!--<div class="NavButtons">
422
- <div class="PrevButton">
423
- <svg fill="none" stroke="currentColor" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
424
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
425
- </svg>
426
- <p>{$_('tournamentsPage.previous')}</p>
427
- </div>
428
- <div class="NextButton">
429
- <p>{$_('tournamentsPage.next')}</p>
430
- <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
431
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
432
- </svg>
433
- </div>
434
- </div>-->
435
- </div>
436
-
437
- <div class="TournamentContentDetails {isMobile(userAgent) ? 'MobileClass' : ''}"
438
- part="TournamentContentDetails {isMobile(userAgent) ? 'MobileClass' : ''}">
439
- <div
440
- class="{isMobile(userAgent) ? 'MobileClass' : ''}{showleaderboard == 'true' ? 'TournamentCardDetails' : 'FullSize'}"
441
- part="{isMobile(userAgent) ? 'MobileClass' : ''}{showleaderboard == 'true' ? 'TournamentCardDetails' : 'FullSize'}">
442
- {#if tournamentDetails}
443
- <casino-tournaments-thumbnail-controller
444
- session={session}
445
- userid={userid}
446
- endpoint={endpoint}
447
- tournamenturl={tournamentDetails.href}
448
- showdetails="false"
449
- showslider="true"
450
- showenrolled="true"
451
- fullsize={!!showleaderboard}
452
- {lang}
453
- {currency}
454
- {keepbrowsercontext}
455
- exportparts="Thumbnail, Status, Enrolled, CardImg, CardImgFinished, Details, Title, Date, ScoreCriteria, Games, TournamentPrizes, TournamentPrizesSvg, a, TournamentPrizesSvgA, PrizesTitle, Prizes, Prize, PrizeText, PrizeRank,
456
- TournamentDuration, TournamentDates, StartDate, EndDate, ProgressBar, ProgressBarFillEnd, Finished, ProgressBarFillStarting, Remaining, ProgressBarFill,
457
- TournamentsGamesSlider, SliderNavButton, items, item, PlayNowButton, itemHover, SliderNavButton
458
- TournamentCard, CardMaxWidth, CardFullSize, elementToFadeOut, elementToFadeIn, ph-item, ph-col-12, ph-picture, ph-row, ph-col-6, big, ph-col-4, empty, ph-col-8, TournamentButtons, LoginButton, RegisterButton, DetailsButton, EnrolledButton, JoinButton, JoinButtonFullSize, spinner, DetailsLargeButton, ErrorText, StatusUnstarted, StatusRunning, StatusClosed, StatusClosing, TournamentPrizesIconSection, TournamentPrizesIconWrapper"
459
- ></casino-tournaments-thumbnail-controller>
460
- {/if}
461
- {#if tournamentDescription.length > 0}
462
- {#each tournamentDescription as desc}
463
- <casino-tournaments-details
464
- title={desc.title}
465
- text={desc.description}
466
- exportparts="DetailsCard, DetailsTitle, Title, CollapseButtonDetails, DetailsContent"
467
- >
468
- </casino-tournaments-details>
469
- {/each}
470
- {/if}
471
- </div>
472
-
473
- <div class="{showleaderboard == 'true' ? 'TournamentTableDetails ' : 'DisplayNone'}"
474
- part="{showleaderboard == 'true' ? 'TournamentTableDetails ' : 'DisplayNone'}">
475
- {#if showleaderboard == "true"}
476
- {#if showTable == true}
477
- <casino-tournaments-table
478
- firstrow="true"
479
- sortable="false"
480
- {lang}
481
- exportparts="TableContent, TableUser, TableHeadRow, TableCell, CurrentUserRow, UnqualifiedRow, TableRank, Rank-1, Rank-2, Rank-3, RankFirstRow, TablePlayer, TablePoints, TablePrize, Qualified, TableUserTooltips, TableUserTooltipsEm, ExclamationMark,
482
- TournamentsTable, LeftTable, LeftTableThead, LeftTableTr, LeftTableTh, LeftTableTd, LeftTableTdEm, LeftTableButton, LeftTableP, LeftTableTbody, FirstRow, RankCol, ScoreChangeFlag, Show, Hidden, Rank_Arror_UP, Rank_Arror_Down, ScoreUp, Flex, RightButton, CollapseButton, TooltipsRow"
483
- ></casino-tournaments-table>
484
- {/if}
485
- {/if}
486
- </div>
487
-
488
- </div>
489
- </div>
490
- </div>
491
- {/if}
492
- {#if isMiniMode }
493
- <div class="TournamentsPage MiniMode {tournamentDetails ? 'hidden':''}" part="MiniTournamentPage">
494
- <div class="TournamentContentDetails {isMobile(userAgent) ? 'MobileClass' : ''}" part="TournamentContentDetails">
495
- <div class="{isMobile(userAgent) ? 'MobileClass' : ''}{showleaderboard == 'true' ? ' TournamentCardDetails' : ' FullSize'}" part="MobileTournamentCardDetails">
496
- {#if !tournamentDetails}
497
- <div class="Thumbnail MiniMode" part="MiniThumbnail">
498
- <img part="CardImg" class="CardImg {(status == 'Closing' || status == 'Closed') ? 'CardImgFinished' : ''}" src="https://i.stack.imgur.com/y9DpT.jpg"
499
- width="65px" height="40px" title="">
500
- <div class="MobileRight" part="ThumbnailRight">
501
- <div class="Title"> </div>
502
- <div>
503
- </div>
504
- </div>
505
- <div class="CloseButton" part="CloseButton" on:click='{()=>closeThumbnail()}'>X</div>
506
- </div>
507
- <casino-tournaments-rank
508
- prize="-"
509
- exportparts="casino-tournaments-rank, Rank, Icon, UserIcon, RankText, Rank_Arror_UP, Rank_Arror_Down, Prize, Icon, PrizeIcon, PrizeText"
510
- ></casino-tournaments-rank>
511
- {/if}
512
- {#if tournamentDetails}
513
- <div class="Thumbnail MiniMode" part="MiniThumbnail">
514
- {#if tournamentDetails.thumbnail}
515
- <img use:matchStatus part="CardImg" class="Mobile CardImg {(tournamentDetails.state == 'Closing' || tournamentDetails.state == 'Closed') ? 'CardImgFinished' : ''}"
516
- src="{tournamentDetails.thumbnail}" width="65px" height="40px" title="{tournamentDetails.nameOrTitle}">
517
- {:else}
518
- <img use:matchStatus part="CardImg" class="CardImg {(tournamentDetails.state == 'Closing' || tournamentDetails.state == 'Closed') ? 'CardImgFinished' : ''}" src="https://i.stack.imgur.com/y9DpT.jpg"
519
- width="65px" height="40px" title="{tournamentDetails.nameOrTitle}">
520
- {/if}
521
- <div class="MobileRight" part="ThumbnailRight">
522
- <div class="Title" part="ThumbnailRight_Title">{tournamentDetails.nameOrTitle}</div>
523
- <div part="ThumbnailRight_Period">
524
- {#if tournamentDetails.startTime}
525
- {$_('tournamentsPage.activePeriod', {values: {startdate: moment(tournamentDetails.startTime).format('DD/MM/YYYY HH:mm'), enddate:moment(tournamentDetails.endTime).format('DD/MM/YYYY HH:mm')}})}
526
- {/if}
527
- </div>
528
- </div>
529
- <div class="CloseButton" part="CloseButton" on:click='{()=>closeThumbnail()}'>X</div>
530
- </div>
531
-
532
- <casino-tournaments-rank part="ThumbnailRank" userrank="{currentUserInPage ? currentUserData.Rank : firstRowData.Rank}" overallrank="{overallRank}"
533
- prize="{currentUserInPage ? (currentUserData.Prize || '-') : (firstRowData.Prize || '-')}" tournamentid="{tourid}"
534
- exportparts="casino-tournaments-rank, Rank, Icon, UserIcon, RankText, Rank_Arror_UP, Rank_Arror_Down, Prize, Icon, PrizeIcon, PrizeText"
535
- ></casino-tournaments-rank>
536
- {/if}
537
- </div>
538
- <casino-tournaments-tab part="ThumbnailTab" use:initTabTitle tabs="leaderboard,rules,games" tab="leaderboard"
539
- exportparts="CustomStylingContainer, ul, li, LiText, sup, SupText, active"
540
- ></casino-tournaments-tab>
541
- <div class="TabContent {showleaderboard == 'true' ? 'TournamentTableDetails ' : 'DisplayNone'} { activeTab != 'leaderboard' ? 'hidden' : ''}" part="ThumbnailTabContent">
542
- <casino-tournaments-table firstrow="true" sortable="false" {lang}
543
- exportparts="TableContent, TableUser, TableHeadRow, TableCell, CurrentUserRow, UnqualifiedRow, TableRank, Rank-1, Rank-2, Rank-3, RankFirstRow, TablePlayer, TablePoints, TablePrize, Qualified, TableUserTooltips, TableUserTooltipsEm, ExclamationMark,
544
- TournamentsTable, LeftTable, LeftTableThead, LeftTableTr, LeftTableTh, LeftTableTd, LeftTableTdEm, LeftTableButton, LeftTableP, LeftTableTbody, FirstRow, RankCol, ScoreChangeFlag, Show, Hidden, Rank_Arror_UP, Rank_Arror_Down, ScoreUp, Flex, RightButton, CollapseButton, TooltipsRow"
545
- ></casino-tournaments-table>
546
- </div>
547
- <div class="TabContent Rules { activeTab != 'rules' ? 'hidden' : ''}" part="ThumbnailTabContent">
548
- {#if tournamentDetails}
549
- <casino-tournaments-thumbnail-rule lang="{lang}" tcurl="{tournamentDetails.termsUrl||'#'}" scorecriterial="{tournamentDetails.scoreCriteria}" betcount="{tournamentDetails.minBetCount || $_('tournamentsPage.unlimited')}"
550
- starttime="{moment(tournamentDetails.startTime).format('DD/MM/YYYY HH:mm:ss')}"
551
- endtime="{moment(tournamentDetails.endTime).format('DD/MM/YYYY HH:mm:ss')}"
552
- products="{tournamentProducts}"
553
- exportparts="casino-tournaments-thumbnail-rule, rule, RuleIcon, RuleTxt"
554
- ></casino-tournaments-thumbnail-rule>
555
- {/if}
556
- </div>
557
- <div class="TabContent Games { activeTab != 'games' ? 'hidden' : ''}" part="ThumbnailTabContent">
558
- {#if tournamentProducts}
559
- <div class="GameItems {tournamentProducts.casino && tournamentProducts.sports ? 'TwoGames' : 'OneGame'}" part="ThumbnailTabContent_Games">
560
- {#if tournamentProducts.casino}
561
- <div part="ThumbnailTabContent_Casino">
562
- <img class="svg" part="ThumbnailTabContent_Games_Casino_Svg" src="{gameCasinoSvg}" width="78" height="75"/>
563
- <span part="ThumbnailTabContent_Games_Casino_Label" on:click='{() => gotoFromTournamentsPage("Casino")}'>{$_('tournamentsPage.forwardCasino')}</span>
564
- </div>
565
- {/if}
566
- {#if tournamentProducts.sports}
567
- <div class="SportsItems" part="ThumbnailTabContent_Sports">
568
- <img class="svg" part="ThumbnailTabContent_Games_Sports_Svg" src="{gameSportsSvg}" width="68" height="65"/>
569
- <span part="ThumbnailTabContent_Games_Sports_Label" on:click='{() => gotoFromTournamentsPage("Sports")}'>{$_('tournamentsPage.forwardSports')}</span>
570
- </div>
571
- {/if}
572
- </div>
573
- {/if}
574
- </div>
575
- <div class="BottomButton" part="ThumbnailGotoTournamentsButton" on:click='{()=>{gotoFromTournamentsPage("MyTournaments")}}' >{$_('tournamentsPage.forwardMyTournaments')}</div>
576
- </div>
577
- </div>
578
- {/if}
579
- <style lang="scss">
580
- :host {
581
- font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
582
- }
583
-
584
- *,
585
- *::before,
586
- *::after {
587
- margin: 0;
588
- padding: 0;
589
- list-style: none;
590
- text-decoration: none;
591
- outline: none;
592
- box-sizing: border-box;
593
- }
594
-
595
- .TournamentsPage {
596
- background: var(--emfe-w-color-contrast, #07072A);
597
- width: 100%;
598
- color: var(--emfe-w-color-white, #FFFFFF);
599
- }
600
-
601
- .TournamentsSectionWrapper {
602
- padding: 24px 0;
603
-
604
- @media screen and (max-width: 1300px) {
605
- padding: 24px 2.4%;
606
- }
607
- }
608
-
609
- .FullSize {
610
- width: 100%;
611
- }
612
-
613
- .DisplayNone {
614
- display: none;
615
- }
616
-
617
- .TopButtons {
618
- display: inline-flex;
619
- flex-direction: column;
620
- padding-bottom: 20px;
621
- font-size: 10px;
622
- }
623
-
624
- .BackButton {
625
- display: inline-flex;
626
- align-items: center;
627
- cursor: pointer;
628
-
629
- p {
630
- font-size: 24px;
631
- }
632
- }
633
-
634
- .NavButtons {
635
- margin-left: auto;
636
- gap: 10px;
637
- display: flex;
638
- }
639
-
640
- .PrevButton {
641
- display: flex;
642
- align-items: center;
643
- border: 1px solid var(--emfe-w-color-white, #FFFFFF);
644
- width: 105px;
645
- height: 36px;
646
- padding: 10px;
647
- font-size: 16px;
648
- cursor: pointer;
649
- }
650
-
651
- .NextButton {
652
- display: flex;
653
- align-items: center;
654
- border: 1px solid var(--emfe-w-color-white, #FFFFFF);
655
- padding: 10px;
656
- width: 75px;
657
- height: 36px;
658
- font-size: 16px;
659
- cursor: pointer;
660
- }
661
-
662
- .TournamentContentDetails {
663
- display: flex;
664
- gap: 20px;
665
-
666
- &.MobileClass {
667
- flex-direction: column;
668
- }
669
- }
670
-
671
- .TournamentCardDetails {
672
- width: 420px;
673
-
674
- &.MobileClass {
675
- width: 100%;
676
- }
677
- }
678
-
679
- .TournamentTableDetails {
680
- flex: auto;
681
- }
682
- .TournamentsPage.MiniMode{
683
- height: max-content;
684
- .MobileClass.TournamentCardDetails{
685
- padding: 5px 5px 0px 5px;
686
- background-color: #333333;
687
- padding-bottom: 12px;
688
- casino-tournaments-rank{display: block;}
689
- }
690
- .CloseButton{position: absolute; right: 3px; top: 3px; font-size: 11px; cursor: pointer}
691
- casino-tournaments-rank::part(Rank), casino-tournaments-rank::part(Prize){
692
- color: #0a0c19;
693
- font-size: 12px;
694
- margin: 0px 0px 0px 5px;
695
- padding: 2px;
696
- }
697
- casino-tournaments-rank::part(Rank){margin-left: 0px; }
698
- casino-tournaments-rank::part(Prize){margin-right: 0px;}
699
- casino-tournaments-rank::part(RankText), casino-tournaments-rank::part(PrizeText){font-weight: 400;}
700
-
701
- .hidden{display: none}
702
- casino-tournaments-thumbnail-controller::part(TournamentCard){
703
- padding: 5px 5px 0px 5px;
704
- background-color: #333333;
705
- }
706
- casino-tournaments-tab::part(LiText){
707
- height: 22px;
708
- top: calc(50% - 22px/2);
709
- font-style: normal;
710
- font-weight: 600;
711
- font-size: 14px;
712
- line-height: 22px;
713
- text-align: center;
714
- letter-spacing: -0.1px;
715
- }
716
- casino-tournaments-tab::part(CustomStylingContainer){
717
- margin-top: 0px;
718
- cursor: pointer;
719
- }
720
- .TabContent, casino-tournaments-tab{padding: 0 16px}
721
- .TabContent.Rules{
722
- padding-bottom: 28px;
723
- }
724
- .TabContent.Games{
725
- padding-bottom: 30px;
726
- .GameItems{
727
- &.OneGame{width: 100%;}
728
- &.TwoGames{width: 100%; display: flex; div{width: 50%}}
729
- text-align: center;
730
- margin: auto;
731
- margin-top: 39px;
732
- span{color: #FF8364; font-size: 12px; text-align: center; text-decoration-line: underline; cursor: pointer; margin-top: 5px}
733
- svg, .svg{height: 70px;display: block;margin: auto;}
734
- svg.ball, .svg.ball{width: 98px}
735
- }
736
- }
737
- .BottomButton{
738
- font-weight: 600;
739
- font-size: 15px;
740
- text-align: center;
741
- height: 35px;
742
- width: 60%;
743
- margin:20px auto;
744
- align-items: center;
745
- padding: 8.72351px 12.6887px;
746
- background: #FF8364;
747
- box-shadow: 0px 0.793047px 2.37914px rgba(0, 0, 0, 0.1), 0px 1.58609px 0.793047px rgba(0, 0, 0, 0.06), 0px 0.793047px 0.793047px rgba(0, 0, 0, 0.07);
748
- border-radius: 4.75828px;
749
- }
750
-
751
- .Thumbnail {
752
- position: relative;
753
- &.Mobile{border: 0px none;
754
- padding: 6px 5px 10px;
755
- background: #333333;}
756
- &.MiniMode .CardImg{margin-bottom: 5px; width: 65px; height: 40px}
757
-
758
- .CardImg {
759
- height: 300px;
760
- width: 100%;
761
- background: url('https://breakthrough.org/wp-content/uploads/2018/10/default-placeholder-image.png');
762
- background-repeat: no-repeat;
763
- background-position: center;
764
- background-size: auto;
765
- &.CardImgFinished {
766
- filter: grayscale(1);
767
- }
768
- &.Mobile{
769
- width: 65px;
770
- height: 40px;
771
- display: inline-block;
772
- }
773
- }
774
- .MobileRight{
775
- display: inline-block;
776
- line-height: 20px;
777
- font-size: 11px;
778
- padding: 2px 3px;
779
- vertical-align: top;
780
- width: calc(100% - 70px);
781
- .Title{text-transform: capitalize; font-size: 14px; font-weight: 600}
782
- }
783
-
784
- .Status {
785
- background: #000000;
786
- display: flex;
787
- justify-content: center;
788
- align-items: center;
789
- position: absolute;
790
- top: 20px;
791
- right: 20px;
792
- min-height: 30px;
793
- padding: 0 10px;
794
- font-size: 12px;
795
- text-transform: uppercase;
796
- z-index: 1;
797
- }
798
-
799
- .Enrolled {
800
- background: #2B2B5D;
801
- color: #aaaabe;
802
- display: flex;
803
- justify-content: center;
804
- align-items: center;
805
- position: absolute;
806
- top: 20px;
807
- left: 20px;
808
- min-height: 30px;
809
- padding: 0 10px;
810
- font-size: 12px;
811
- text-transform: uppercase;
812
- z-index: 1;
813
- }
814
- }
815
- }
816
-
817
- </style>
1
+ <svelte:options tag={null}/>
2
+
3
+ <script lang="ts">
4
+ import { onMount } from 'svelte';
5
+ import moment from 'moment';
6
+ import { isMobile, getDevice, checkSession } from 'rvhelper';
7
+ import { _, addNewMessages, date, setLocale, setupI18n } from './i18n';
8
+ import { TournamentsPageTranslations } from './translations';
9
+ import { EventSourcePolyfill } from 'event-source-polyfill';
10
+
11
+ import gameCasinoSvg from './images/game-casino.svg';
12
+ import gameSportsSvg from './images/game-sports.svg'
13
+
14
+ import '@everymatrix/casino-tournaments-details';
15
+ import '@everymatrix/casino-tournaments-thumbnail-controller';
16
+ import '@everymatrix/casino-tournaments-table';
17
+ import '@everymatrix/casino-tournaments-tab';
18
+ import '@everymatrix/casino-tournaments-thumbnail-rule';
19
+ import '@everymatrix/casino-tournaments-rank';
20
+
21
+ export let session: string = '';
22
+ export let userid: string = '';
23
+ export let tourid: string = '';
24
+ export let endpoint: string = '';
25
+ export let showleaderboard: string = '';
26
+ export let cmsendpoint: string = '';
27
+ export let lang: string = '';
28
+ export let navigationbackbutton: string = 'Default';
29
+ export let currency: string = 'EUR';
30
+ export let tablelimit: string = '30';
31
+ export let namemask: string = '';
32
+ export let showunqualifiedplayer: string = 'true'
33
+ export let mobiletablelimit:string = '15';
34
+ export let updatetableintime:string = 'true';
35
+ export let viewmode:string = '';
36
+ export let minscore:string = '';
37
+
38
+ export let leaderboardoffset:string = '0';
39
+ export let leaderboardlimit:string = '15';
40
+ export let keepbrowsercontext:string = 'false';
41
+ // Variables of topics for communication
42
+ let sessionTopic;
43
+
44
+ let isLoggedIn: boolean = false;
45
+ let sessionID: string = '';
46
+ let playerID: string = '';
47
+ let isLoading: boolean = true;
48
+ let tournamentDescription: Array<any> = [];
49
+ let tournamentProducts:any;
50
+
51
+ let tournamentDetails: any = undefined;
52
+ let tournamentTableData: any = undefined;
53
+
54
+ let userAgent = window.navigator.userAgent;
55
+
56
+ let showTable: boolean = false;
57
+ let firstRowData: any = {};
58
+ let firstRowAvailable: boolean = false;
59
+
60
+ let tableUpdateEventSource: any;
61
+ let tournamentUpdateEventSource:EventSourcePolyfill;
62
+
63
+ let currentUserData:any = {};
64
+ let currentUserInPage:Boolean = false;
65
+ let activeTab = 'leaderboard';
66
+ let overallRank:number;
67
+ let latestRank:number;
68
+ let isMiniMode:boolean;
69
+ let shownStatus:any = '';
70
+
71
+ setupI18n({ withLocale: 'en', translations: {}});
72
+
73
+ Object.keys(TournamentsPageTranslations).forEach((item: any) => {
74
+ addNewMessages(item, TournamentsPageTranslations[item]);
75
+ });
76
+
77
+ // @TODO this must be configurable
78
+ const tableColumns = ['Rank', 'Player', 'Points','Prize'];
79
+ // data for current user
80
+ const transFormCurrentUserData = (item:any) => {
81
+ let userData = {
82
+ Rank: showunqualifiedplayer == "false" ? item.rankWithoutUnqualified : item.rank,
83
+ Player: item.shortName,
84
+ Points: item.score,
85
+ Prize: item.prizeName,
86
+ Unqualified: item.unqualified,
87
+ BetCount: item.betCount,
88
+ userID: item.userID
89
+ };
90
+ return userData;
91
+ }
92
+
93
+ const transFormCurrentUserDataAtFistRow = (item: any) => ({
94
+ ...transFormCurrentUserData(item),
95
+ ...(item.unqualified === true ? { Rank: item.rank } : {})
96
+ })
97
+
98
+ // @TODO data type
99
+ const transformTableData = (data:any) => {
100
+
101
+ currentUserInPage = false
102
+
103
+ let tableData:any = [];
104
+
105
+ if (data && data.length > 0) {
106
+ data.forEach((item:any) => {
107
+ let transformedItem = transFormCurrentUserData(item)
108
+ if(item.userID == playerID){
109
+ currentUserData = transformedItem;
110
+ currentUserInPage = true;
111
+ }
112
+ tableData.push(transformedItem);
113
+ });
114
+ }
115
+
116
+ return tableData;
117
+ },
118
+ tournamentUpdateMessageHandler= (message:any) =>{
119
+ if(!message.data){
120
+ return;
121
+ }
122
+ try{
123
+ let messagDataAsJson = JSON.parse(message.data);
124
+ if(messagDataAsJson.messageType == 'TournamentUpdate'){
125
+ window.postMessage({type: 'UpdateTournamentView', tournamentData: messagDataAsJson.item}, window.location.href);
126
+ tournamentDetails = messagDataAsJson.item;
127
+ transformTournamentData(messagDataAsJson.item);
128
+ matchStatus();
129
+ }
130
+ }catch (e){
131
+ console.error(e);
132
+ }
133
+ },
134
+ startupTournamentUpdateListener = (tournamentID: string, searchParams:any)=>{
135
+ let endpointURL:string = `${endpoint}/tournaments/updates?filter=id=${tournamentID}&${searchParams.toString()}&XSessionId=${session}`;
136
+ if(!EventSource){
137
+ tournamentUpdateEventSource = new EventSourcePolyfill(endpointURL,{headers: {'accept': 'text/event-stream'}});
138
+ }else{
139
+ tournamentUpdateEventSource = new EventSource(endpointURL);
140
+ }
141
+ if (!typeof (tournamentUpdateEventSource) != 'undefined'){
142
+ tournamentUpdateEventSource.addEventListener('message', tournamentUpdateMessageHandler);
143
+ }
144
+ },
145
+ tableUpdateMessageHandler = (message:any)=>{
146
+ if(!message.data){
147
+ return;
148
+ }
149
+ try{
150
+ let messageData:any = message.data;
151
+ let updateTableData:any = JSON.parse(messageData);
152
+ if(!updateTableData || !updateTableData.items){
153
+ return;
154
+ }
155
+ let newTableData: Array<LeaderboardRow> = transformTableData(updateTableData.items);
156
+ window.postMessage({ type: 'CasinoTableData', tableData: newTableData }, window.location.href);
157
+ currentUserInPage = newTableData.filter((item)=>{
158
+ return item.userID = playerID;
159
+ }).length > 0;
160
+ if(updateTableData.item){
161
+ firstRowAvailable = true;
162
+ firstRowData = transFormCurrentUserDataAtFistRow(updateTableData.item);
163
+ if(firstRowData){
164
+ window.postMessage({ type: 'CasinoTableFirstRowData', tableData: firstRowData }, window.location.href);
165
+ }
166
+ }
167
+
168
+ let newUserRank = currentUserInPage ? currentUserData.Rank : firstRowData.Rank;
169
+ if(newUserRank != latestRank || overallRank != updateTableData.items.length){
170
+ overallRank = updateTableData.items.length;//new player joined and spined
171
+ window.postMessage({type: `TournamentRankInfo_${tourid}`, rankInfo:{
172
+ rank: newUserRank,
173
+ overallRank: overallRank,
174
+ prize: currentUserInPage ? (currentUserData.Prize || '-') : (firstRowData.Prize || '-')
175
+ }});
176
+ latestRank = newUserRank;
177
+ }
178
+
179
+ if(currentUserInPage){
180
+ window.postMessage({ type: 'CasinoTableCurrentUserData', tableData: currentUserData }, window.location.href);
181
+ }
182
+ }catch(err){
183
+ console.error(err);
184
+ }
185
+ },
186
+ startupTableDataChangeListener = (tournamentID: String, searchParams: any) => {
187
+ let endpointURL: String = `${endpoint}/tournaments/${tournamentID}/leaderboard/updates?HeartBeat=false&XSessionId=${session}&${searchParams.toString()}`;
188
+ if(tableUpdateEventSource){
189
+ return;
190
+ }
191
+ if(!EventSource){
192
+ tableUpdateEventSource = new EventSourcePolyfill(endpointURL,{headers: {'accept': 'text/event-stream'}});
193
+ }else{
194
+ tableUpdateEventSource = new EventSource(endpointURL);
195
+ }
196
+ if (typeof (tableUpdateEventSource) != "undefined") {
197
+ tableUpdateEventSource.addEventListener('open', tableUpdateMessageHandler);
198
+ tableUpdateEventSource.addEventListener('message', tableUpdateMessageHandler);
199
+ tableUpdateEventSource.addEventListener('error', tableUpdateMessageHandler);
200
+ }
201
+ },
202
+ transformTournamentData = (data:any)=>{
203
+ let productInfo={};
204
+ if(data.wallet){
205
+ let wallet = data.wallet;
206
+ if(wallet.casino){
207
+ productInfo['casino'] = {
208
+ name: 'Casino',
209
+ minbet: wallet.casino.minStake && wallet.casino.minStake.amount ? wallet.casino.minStake.amount.EUR : $_('tournamentsPage.unlimited'),
210
+ maxbet: wallet.casino.maxStake && wallet.casino.maxStake.amount ? wallet.casino.maxStake.amount.EUR : $_('tournamentsPage.unlimited')
211
+ }
212
+ }
213
+ if(wallet.sports){
214
+ productInfo['sports'] = {
215
+ name: 'Sports',
216
+ minbet: wallet.sports.minStake && wallet.sports.minStake.amount ? wallet.sports.minStake.amount.EUR : $_('tournamentsPage.unlimited'),
217
+ maxbet: wallet.sports.maxStake && wallet.sports.maxStake.amount ? wallet.sports.maxStake.amount.EUR : $_('tournamentsPage.unlimited')
218
+ }
219
+ }
220
+ tournamentProducts = productInfo;
221
+ }
222
+ }
223
+
224
+ const getData = (endpointURL: String, tourID: String) => {
225
+ let url = new URL(endpointURL + `/tournaments/${tourID}`);
226
+ let reqHeaders = new Headers({'X-SessionId': session});
227
+
228
+ url.searchParams.append('expand', 'games');
229
+ url.searchParams.append('language', lang);
230
+ url.searchParams.append('platform', getDevice(userAgent));
231
+
232
+ let requestOptions = {
233
+ method: 'GET',
234
+ headers: reqHeaders,
235
+ };
236
+
237
+ fetch(url.href, requestOptions)
238
+ .then((res: any) => res.json())
239
+ .then((res: any) => {
240
+ tournamentDetails = res.item;
241
+ transformTournamentData(tournamentDetails);
242
+ startupTournamentUpdateListener(tourid, url.searchParams);
243
+ });
244
+ }
245
+
246
+ const getTableData = (endpointURL: String, tourID: String) => {
247
+ let url = new URL(endpointURL + `/tournaments/${tourID}/leaderboard`);
248
+ let reqHeaders = new Headers();
249
+
250
+ url.searchParams.append('language', lang);
251
+
252
+ let tableFilter = `includeUnqualifiedPlayer=${showunqualifiedplayer}`;
253
+ tableFilter = namemask ? `${tableFilter},shortNameMask=${namemask}` : tableFilter;
254
+ tableFilter = minscore ? `${tableFilter},minscore=${minscore}` : tableFilter;
255
+
256
+ url.searchParams.append('filter', tableFilter);
257
+
258
+ if (session) {
259
+ let limit = isMobile(userAgent) == true? mobiletablelimit : tablelimit;
260
+ url.searchParams.append('pagination', `offset=0,limit=${limit}`);
261
+ reqHeaders.append('X-SessionId', session);
262
+ }
263
+ url.searchParams.append('platform', getDevice(userAgent));
264
+
265
+ let requestOptions = {
266
+ method: 'GET',
267
+ headers: reqHeaders,
268
+ };
269
+
270
+ fetch(url, requestOptions)
271
+ .then((res: any) => res.json())
272
+ .then((res: any) => {
273
+ tournamentTableData = transformTableData(res.items);
274
+ if(res.item && !currentUserInPage){
275
+ firstRowAvailable = true;
276
+ firstRowData = transFormCurrentUserDataAtFistRow(res.item);
277
+ }
278
+ showTable = true;
279
+ latestRank = currentUserInPage ? currentUserData.Rank : firstRowData.Rank
280
+ overallRank = res.total;
281
+
282
+ // @TODO data is not iterable error fix
283
+ window.postMessage({
284
+ type: 'CasinoTableData',
285
+ tableData: tournamentTableData
286
+ }, window.location.href);
287
+ window.postMessage({type: 'CasinoTableColumns', tableColumns}, window.location.href);
288
+ if (firstRowAvailable) {
289
+ window.postMessage({type: 'CasinoTableFirstRowData', tableData: firstRowData}, window.location.href);
290
+ }
291
+ if(updatetableintime === 'true'){
292
+ startupTableDataChangeListener(tourID, url.searchParams);
293
+ }
294
+ if (currentUserInPage){
295
+ window.postMessage({ type: 'CasinoTableCurrentUserData', tableData: currentUserData }, window.location.href);
296
+ }
297
+ });
298
+ }
299
+
300
+ const messageHandler = (e: any) => {
301
+ if (e.data && e.data.type == 'UserSessionID') {
302
+ isLoggedIn = true;
303
+ sessionID = e.data.session;
304
+ }
305
+
306
+ if (e.data && e.data.type == 'PlayerID') {
307
+ playerID = e.data.playerID;
308
+ }
309
+ if(e.data && e.data.type == 'TournamentsTabSwitch'){
310
+ activeTab = e.data.tab;
311
+ }
312
+ }
313
+
314
+ const matchStatus = () => {
315
+ if (tournamentDetails.state == 'Unstarted') {
316
+ shownStatus = $_('tournamentsPage.scheduled');
317
+ }
318
+
319
+ if (tournamentDetails.state == 'Running') {
320
+ shownStatus = $_('tournamentsPage.ongoing');
321
+ }
322
+
323
+ if (tournamentDetails.state == 'Closed' || tournamentDetails.state == 'Closing') {
324
+ shownStatus = $_('tournamentsPage.finished');
325
+ }
326
+ }
327
+
328
+ const goBack = () => {
329
+ // this function handles the back navigation making use of the prop: navigationbackbutton. If it has the
330
+ // event value, it will emit the 'RedirectBack' event which will enable the client to handle the routing;
331
+ // else, if it has the 'Default' value, it will do a window.history.back()
332
+ if (navigationbackbutton == 'Event') {
333
+ window.postMessage({type: 'RedirectBack'}, window.location.href);
334
+ } else if (navigationbackbutton == 'Default') {
335
+ window.history.back();
336
+ }
337
+ }
338
+ const closeThumbnail = () =>{
339
+ window.postMessage({ type: 'OnCloseThumbnail' }, window.location.href);
340
+ }
341
+ const gotoFromTournamentsPage = (pageType: string) =>{
342
+ window.postMessage({ type: 'GotoFromTournamentsPage', pageType }, window.location.href);
343
+ }
344
+
345
+ const setSession = () => {
346
+ if (session.length > 0 && session != 'false') {
347
+ sessionID = session;
348
+ playerID = userid;
349
+ isLoggedIn = true;
350
+ } else {
351
+ isLoggedIn = false;
352
+ }
353
+
354
+ isLoading = false;
355
+ }
356
+ const setActiveLanguage = ():void => {
357
+ setLocale(lang);
358
+ initTabTitle()
359
+ }
360
+ const initialLoad = () => {
361
+ setLocale(lang);
362
+ getData(endpoint, tourid);
363
+ getTableData(endpoint, tourid);
364
+ }
365
+
366
+ const getDataFromCMS = () => {
367
+ fetch(`${cmsendpoint}/${tourid}`)
368
+ .then((res: any) => res.json())
369
+ .then((data: any) => {
370
+ if (data && data.details) {
371
+ tournamentDescription = data.details;
372
+ }
373
+ });
374
+ }
375
+ const initTabTitle= () =>{
376
+ window.postMessage({type: 'TournamentsTabLocaleTextUpdate','state': 'leaderboard', 'text': $_('tournamentsPage.leaderBoard')}, window.location.href)
377
+ window.postMessage({type: 'TournamentsTabLocaleTextUpdate','state': 'rules', 'text': $_('tournamentsPage.rules')}, window.location.href)
378
+ window.postMessage({type: 'TournamentsTabLocaleTextUpdate','state': 'games', 'text': $_('tournamentsPage.games')}, window.location.href)
379
+ }
380
+
381
+ onMount(() => {
382
+ window.addEventListener('message', messageHandler, false);
383
+ return () => {
384
+ window.removeEventListener('message', messageHandler);
385
+ if(tableUpdateEventSource){
386
+ tableUpdateEventSource.removeEventListener('open', tableUpdateMessageHandler);
387
+ tableUpdateEventSource.removeEventListener('message', tableUpdateMessageHandler);
388
+ tableUpdateEventSource.removeEventListener('error', tableUpdateMessageHandler);
389
+ }
390
+ if(tournamentUpdateEventSource){
391
+ tournamentUpdateEventSource.removeEventListener('message', tournamentUpdateMessageHandler);
392
+ }
393
+ }
394
+ });
395
+
396
+ $: session && userid && setSession();
397
+ $: lang && setActiveLanguage();
398
+ $: initialParameters = tourid && endpoint && session && lang;
399
+ $: initialParameters && initialLoad();
400
+ $: cmsendpoint && tourid && getDataFromCMS();
401
+ $: isMiniMode = (viewmode != 'desktop') && isMobile(userAgent); // forward this page from tournamentslider
402
+ </script>
403
+
404
+ {#if isLoading}
405
+ <p class="LoadingMessage" part="LoadingMessage">
406
+ {$_('tournamentsPage.loading')}
407
+ </p>
408
+ {/if}
409
+ {#if !isMiniMode}
410
+ <div class="TournamentsPage" part="TournamentsPage">
411
+ <div class="TournamentsSectionWrapper" part="TournamentsSectionWrapper">
412
+
413
+ <div class="TopButtons" part="TopButtons">
414
+ <div class="BackButton" part="BackButton" on:click={() => goBack()}>
415
+ <svg fill="none" stroke="currentColor" width="24" height="24" viewBox="0 0 24 24"
416
+ xmlns="http://www.w3.org/2000/svg">
417
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
418
+ </svg>
419
+ <p>{$_('tournamentsPage.back')}</p>
420
+ </div>
421
+ <!--<div class="NavButtons">
422
+ <div class="PrevButton">
423
+ <svg fill="none" stroke="currentColor" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
424
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
425
+ </svg>
426
+ <p>{$_('tournamentsPage.previous')}</p>
427
+ </div>
428
+ <div class="NextButton">
429
+ <p>{$_('tournamentsPage.next')}</p>
430
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
431
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
432
+ </svg>
433
+ </div>
434
+ </div>-->
435
+ </div>
436
+
437
+ <div class="TournamentContentDetails {isMobile(userAgent) ? 'MobileClass' : ''}"
438
+ part="TournamentContentDetails {isMobile(userAgent) ? 'MobileClass' : ''}">
439
+ <div
440
+ class="{isMobile(userAgent) ? 'MobileClass' : ''}{showleaderboard == 'true' ? 'TournamentCardDetails' : 'FullSize'}"
441
+ part="{isMobile(userAgent) ? 'MobileClass' : ''}{showleaderboard == 'true' ? 'TournamentCardDetails' : 'FullSize'}">
442
+ {#if tournamentDetails}
443
+ <casino-tournaments-thumbnail-controller
444
+ session={session}
445
+ userid={userid}
446
+ endpoint={endpoint}
447
+ tournamenturl={tournamentDetails.href}
448
+ showdetails="false"
449
+ showslider="true"
450
+ showenrolled="true"
451
+ fullsize={!!showleaderboard}
452
+ {lang}
453
+ {currency}
454
+ {keepbrowsercontext}
455
+ exportparts="Thumbnail, Status, Enrolled, CardImg, CardImgFinished, Details, Title, Date, ScoreCriteria, Games, TournamentPrizes, TournamentPrizesSvg, a, TournamentPrizesSvgA, PrizesTitle, Prizes, Prize, PrizeText, PrizeRank,
456
+ TournamentDuration, TournamentDates, StartDate, EndDate, ProgressBar, ProgressBarFillEnd, Finished, ProgressBarFillStarting, Remaining, ProgressBarFill,
457
+ TournamentsGamesSlider, SliderNavButton, items, item, PlayNowButton, itemHover, SliderNavButton
458
+ TournamentCard, CardMaxWidth, CardFullSize, elementToFadeOut, elementToFadeIn, ph-item, ph-col-12, ph-picture, ph-row, ph-col-6, big, ph-col-4, empty, ph-col-8, TournamentButtons, LoginButton, RegisterButton, DetailsButton, EnrolledButton, JoinButton, JoinButtonFullSize, spinner, DetailsLargeButton, ErrorText, StatusUnstarted, StatusRunning, StatusClosed, StatusClosing, TournamentPrizesIconSection, TournamentPrizesIconWrapper"
459
+ ></casino-tournaments-thumbnail-controller>
460
+ {/if}
461
+ {#if tournamentDescription.length > 0}
462
+ {#each tournamentDescription as desc}
463
+ <casino-tournaments-details
464
+ title={desc.title}
465
+ text={desc.description}
466
+ exportparts="DetailsCard, DetailsTitle, Title, CollapseButtonDetails, DetailsContent"
467
+ >
468
+ </casino-tournaments-details>
469
+ {/each}
470
+ {/if}
471
+ </div>
472
+
473
+ <div class="{showleaderboard == 'true' ? 'TournamentTableDetails ' : 'DisplayNone'}"
474
+ part="{showleaderboard == 'true' ? 'TournamentTableDetails ' : 'DisplayNone'}">
475
+ {#if showleaderboard == "true"}
476
+ {#if showTable == true}
477
+ <casino-tournaments-table
478
+ firstrow="true"
479
+ sortable="false"
480
+ {lang}
481
+ exportparts="TableContent, TableUser, TableHeadRow, TableCell, CurrentUserRow, UnqualifiedRow, TableRank, Rank-1, Rank-2, Rank-3, RankFirstRow, TablePlayer, TablePoints, TablePrize, Qualified, TableUserTooltips, TableUserTooltipsEm, ExclamationMark,
482
+ TournamentsTable, LeftTable, LeftTableThead, LeftTableTr, LeftTableTh, LeftTableTd, LeftTableTdEm, LeftTableButton, LeftTableP, LeftTableTbody, FirstRow, RankCol, ScoreChangeFlag, Show, Hidden, Rank_Arror_UP, Rank_Arror_Down, ScoreUp, Flex, RightButton, CollapseButton, TooltipsRow"
483
+ ></casino-tournaments-table>
484
+ {/if}
485
+ {/if}
486
+ </div>
487
+
488
+ </div>
489
+ </div>
490
+ </div>
491
+ {/if}
492
+ {#if isMiniMode }
493
+ <div class="TournamentsPage MiniMode {tournamentDetails ? 'hidden':''}" part="MiniTournamentPage">
494
+ <div class="TournamentContentDetails {isMobile(userAgent) ? 'MobileClass' : ''}" part="TournamentContentDetails">
495
+ <div class="{isMobile(userAgent) ? 'MobileClass' : ''}{showleaderboard == 'true' ? ' TournamentCardDetails' : ' FullSize'}" part="MobileTournamentCardDetails">
496
+ {#if !tournamentDetails}
497
+ <div class="Thumbnail MiniMode" part="MiniThumbnail">
498
+ <img part="CardImg" class="CardImg {(status == 'Closing' || status == 'Closed') ? 'CardImgFinished' : ''}" src="https://i.stack.imgur.com/y9DpT.jpg"
499
+ width="65px" height="40px" title="">
500
+ <div class="MobileRight" part="ThumbnailRight">
501
+ <div class="Title"> </div>
502
+ <div>
503
+ </div>
504
+ </div>
505
+ <div class="CloseButton" part="CloseButton" on:click='{()=>closeThumbnail()}'>X</div>
506
+ </div>
507
+ <casino-tournaments-rank
508
+ prize="-"
509
+ exportparts="casino-tournaments-rank, Rank, Icon, UserIcon, RankText, Rank_Arror_UP, Rank_Arror_Down, Prize, Icon, PrizeIcon, PrizeText"
510
+ ></casino-tournaments-rank>
511
+ {/if}
512
+ {#if tournamentDetails}
513
+ <div class="Thumbnail MiniMode" part="MiniThumbnail">
514
+ {#if tournamentDetails.thumbnail}
515
+ <img use:matchStatus part="CardImg" class="Mobile CardImg {(tournamentDetails.state == 'Closing' || tournamentDetails.state == 'Closed') ? 'CardImgFinished' : ''}"
516
+ src="{tournamentDetails.thumbnail}" width="65px" height="40px" title="{tournamentDetails.nameOrTitle}">
517
+ {:else}
518
+ <img use:matchStatus part="CardImg" class="CardImg {(tournamentDetails.state == 'Closing' || tournamentDetails.state == 'Closed') ? 'CardImgFinished' : ''}" src="https://i.stack.imgur.com/y9DpT.jpg"
519
+ width="65px" height="40px" title="{tournamentDetails.nameOrTitle}">
520
+ {/if}
521
+ <div class="MobileRight" part="ThumbnailRight">
522
+ <div class="Title" part="ThumbnailRight_Title">{tournamentDetails.nameOrTitle}</div>
523
+ <div part="ThumbnailRight_Period">
524
+ {#if tournamentDetails.startTime}
525
+ {$_('tournamentsPage.activePeriod', {values: {startdate: moment(tournamentDetails.startTime).format('DD/MM/YYYY HH:mm'), enddate:moment(tournamentDetails.endTime).format('DD/MM/YYYY HH:mm')}})}
526
+ {/if}
527
+ </div>
528
+ </div>
529
+ <div class="CloseButton" part="CloseButton" on:click='{()=>closeThumbnail()}'>X</div>
530
+ </div>
531
+
532
+ <casino-tournaments-rank part="ThumbnailRank" userrank="{currentUserInPage ? currentUserData.Rank : firstRowData.Rank}" overallrank="{overallRank}"
533
+ prize="{currentUserInPage ? (currentUserData.Prize || '-') : (firstRowData.Prize || '-')}" tournamentid="{tourid}"
534
+ exportparts="casino-tournaments-rank, Rank, Icon, UserIcon, RankText, Rank_Arror_UP, Rank_Arror_Down, Prize, Icon, PrizeIcon, PrizeText"
535
+ ></casino-tournaments-rank>
536
+ {/if}
537
+ </div>
538
+ <casino-tournaments-tab part="ThumbnailTab" use:initTabTitle tabs="leaderboard,rules,games" tab="leaderboard"
539
+ exportparts="CustomStylingContainer, ul, li, LiText, sup, SupText, active"
540
+ ></casino-tournaments-tab>
541
+ <div class="TabContent {showleaderboard == 'true' ? 'TournamentTableDetails ' : 'DisplayNone'} { activeTab != 'leaderboard' ? 'hidden' : ''}" part="ThumbnailTabContent">
542
+ <casino-tournaments-table firstrow="true" sortable="false" {lang}
543
+ exportparts="TableContent, TableUser, TableHeadRow, TableCell, CurrentUserRow, UnqualifiedRow, TableRank, Rank-1, Rank-2, Rank-3, RankFirstRow, TablePlayer, TablePoints, TablePrize, Qualified, TableUserTooltips, TableUserTooltipsEm, ExclamationMark,
544
+ TournamentsTable, LeftTable, LeftTableThead, LeftTableTr, LeftTableTh, LeftTableTd, LeftTableTdEm, LeftTableButton, LeftTableP, LeftTableTbody, FirstRow, RankCol, ScoreChangeFlag, Show, Hidden, Rank_Arror_UP, Rank_Arror_Down, ScoreUp, Flex, RightButton, CollapseButton, TooltipsRow"
545
+ ></casino-tournaments-table>
546
+ </div>
547
+ <div class="TabContent Rules { activeTab != 'rules' ? 'hidden' : ''}" part="ThumbnailTabContent">
548
+ {#if tournamentDetails}
549
+ <casino-tournaments-thumbnail-rule lang="{lang}" tcurl="{tournamentDetails.termsUrl||'#'}" scorecriterial="{tournamentDetails.scoreCriteria}" betcount="{tournamentDetails.minBetCount || $_('tournamentsPage.unlimited')}"
550
+ starttime="{moment(tournamentDetails.startTime).format('DD/MM/YYYY HH:mm:ss')}"
551
+ endtime="{moment(tournamentDetails.endTime).format('DD/MM/YYYY HH:mm:ss')}"
552
+ products="{tournamentProducts}"
553
+ exportparts="casino-tournaments-thumbnail-rule, rule, RuleIcon, RuleTxt"
554
+ ></casino-tournaments-thumbnail-rule>
555
+ {/if}
556
+ </div>
557
+ <div class="TabContent Games { activeTab != 'games' ? 'hidden' : ''}" part="ThumbnailTabContent">
558
+ {#if tournamentProducts}
559
+ <div class="GameItems {tournamentProducts.casino && tournamentProducts.sports ? 'TwoGames' : 'OneGame'}" part="ThumbnailTabContent_Games">
560
+ {#if tournamentProducts.casino}
561
+ <div part="ThumbnailTabContent_Casino">
562
+ <img class="svg" part="ThumbnailTabContent_Games_Casino_Svg" src="{gameCasinoSvg}" width="78" height="75"/>
563
+ <span part="ThumbnailTabContent_Games_Casino_Label" on:click='{() => gotoFromTournamentsPage("Casino")}'>{$_('tournamentsPage.forwardCasino')}</span>
564
+ </div>
565
+ {/if}
566
+ {#if tournamentProducts.sports}
567
+ <div class="SportsItems" part="ThumbnailTabContent_Sports">
568
+ <img class="svg" part="ThumbnailTabContent_Games_Sports_Svg" src="{gameSportsSvg}" width="68" height="65"/>
569
+ <span part="ThumbnailTabContent_Games_Sports_Label" on:click='{() => gotoFromTournamentsPage("Sports")}'>{$_('tournamentsPage.forwardSports')}</span>
570
+ </div>
571
+ {/if}
572
+ </div>
573
+ {/if}
574
+ </div>
575
+ <div class="BottomButton" part="ThumbnailGotoTournamentsButton" on:click='{()=>{gotoFromTournamentsPage("MyTournaments")}}' >{$_('tournamentsPage.forwardMyTournaments')}</div>
576
+ </div>
577
+ </div>
578
+ {/if}
579
+ <style lang="scss">
580
+ :host {
581
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
582
+ }
583
+
584
+ *,
585
+ *::before,
586
+ *::after {
587
+ margin: 0;
588
+ padding: 0;
589
+ list-style: none;
590
+ text-decoration: none;
591
+ outline: none;
592
+ box-sizing: border-box;
593
+ }
594
+
595
+ .TournamentsPage {
596
+ background: var(--emfe-w-color-contrast, #07072A);
597
+ width: 100%;
598
+ color: var(--emfe-w-color-white, #FFFFFF);
599
+ }
600
+
601
+ .TournamentsSectionWrapper {
602
+ padding: 24px 0;
603
+
604
+ @media screen and (max-width: 1300px) {
605
+ padding: 24px 2.4%;
606
+ }
607
+ }
608
+
609
+ .FullSize {
610
+ width: 100%;
611
+ }
612
+
613
+ .DisplayNone {
614
+ display: none;
615
+ }
616
+
617
+ .TopButtons {
618
+ display: inline-flex;
619
+ flex-direction: column;
620
+ padding-bottom: 20px;
621
+ font-size: 10px;
622
+ }
623
+
624
+ .BackButton {
625
+ display: inline-flex;
626
+ align-items: center;
627
+ cursor: pointer;
628
+
629
+ p {
630
+ font-size: 24px;
631
+ }
632
+ }
633
+
634
+ .NavButtons {
635
+ margin-left: auto;
636
+ gap: 10px;
637
+ display: flex;
638
+ }
639
+
640
+ .PrevButton {
641
+ display: flex;
642
+ align-items: center;
643
+ border: 1px solid var(--emfe-w-color-white, #FFFFFF);
644
+ width: 105px;
645
+ height: 36px;
646
+ padding: 10px;
647
+ font-size: 16px;
648
+ cursor: pointer;
649
+ }
650
+
651
+ .NextButton {
652
+ display: flex;
653
+ align-items: center;
654
+ border: 1px solid var(--emfe-w-color-white, #FFFFFF);
655
+ padding: 10px;
656
+ width: 75px;
657
+ height: 36px;
658
+ font-size: 16px;
659
+ cursor: pointer;
660
+ }
661
+
662
+ .TournamentContentDetails {
663
+ display: flex;
664
+ gap: 20px;
665
+
666
+ &.MobileClass {
667
+ flex-direction: column;
668
+ }
669
+ }
670
+
671
+ .TournamentCardDetails {
672
+ width: 420px;
673
+
674
+ &.MobileClass {
675
+ width: 100%;
676
+ }
677
+ }
678
+
679
+ .TournamentTableDetails {
680
+ flex: auto;
681
+ }
682
+ .TournamentsPage.MiniMode{
683
+ height: max-content;
684
+ .MobileClass.TournamentCardDetails{
685
+ padding: 5px 5px 0px 5px;
686
+ background-color: #333333;
687
+ padding-bottom: 12px;
688
+ casino-tournaments-rank{display: block;}
689
+ }
690
+ .CloseButton{position: absolute; right: 3px; top: 3px; font-size: 11px; cursor: pointer}
691
+ casino-tournaments-rank::part(Rank), casino-tournaments-rank::part(Prize){
692
+ color: #0a0c19;
693
+ font-size: 12px;
694
+ margin: 0px 0px 0px 5px;
695
+ padding: 2px;
696
+ }
697
+ casino-tournaments-rank::part(Rank){margin-left: 0px; }
698
+ casino-tournaments-rank::part(Prize){margin-right: 0px;}
699
+ casino-tournaments-rank::part(RankText), casino-tournaments-rank::part(PrizeText){font-weight: 400;}
700
+
701
+ .hidden{display: none}
702
+ casino-tournaments-thumbnail-controller::part(TournamentCard){
703
+ padding: 5px 5px 0px 5px;
704
+ background-color: #333333;
705
+ }
706
+ casino-tournaments-tab::part(LiText){
707
+ height: 22px;
708
+ top: calc(50% - 22px/2);
709
+ font-style: normal;
710
+ font-weight: 600;
711
+ font-size: 14px;
712
+ line-height: 22px;
713
+ text-align: center;
714
+ letter-spacing: -0.1px;
715
+ }
716
+ casino-tournaments-tab::part(CustomStylingContainer){
717
+ margin-top: 0px;
718
+ cursor: pointer;
719
+ }
720
+ .TabContent, casino-tournaments-tab{padding: 0 16px}
721
+ .TabContent.Rules{
722
+ padding-bottom: 28px;
723
+ }
724
+ .TabContent.Games{
725
+ padding-bottom: 30px;
726
+ .GameItems{
727
+ &.OneGame{width: 100%;}
728
+ &.TwoGames{width: 100%; display: flex; div{width: 50%}}
729
+ text-align: center;
730
+ margin: auto;
731
+ margin-top: 39px;
732
+ span{color: #FF8364; font-size: 12px; text-align: center; text-decoration-line: underline; cursor: pointer; margin-top: 5px}
733
+ svg, .svg{height: 70px;display: block;margin: auto;}
734
+ svg.ball, .svg.ball{width: 98px}
735
+ }
736
+ }
737
+ .BottomButton{
738
+ font-weight: 600;
739
+ font-size: 15px;
740
+ text-align: center;
741
+ height: 35px;
742
+ width: 60%;
743
+ margin:20px auto;
744
+ align-items: center;
745
+ padding: 8.72351px 12.6887px;
746
+ background: #FF8364;
747
+ box-shadow: 0px 0.793047px 2.37914px rgba(0, 0, 0, 0.1), 0px 1.58609px 0.793047px rgba(0, 0, 0, 0.06), 0px 0.793047px 0.793047px rgba(0, 0, 0, 0.07);
748
+ border-radius: 4.75828px;
749
+ }
750
+
751
+ .Thumbnail {
752
+ position: relative;
753
+ &.Mobile{border: 0px none;
754
+ padding: 6px 5px 10px;
755
+ background: #333333;}
756
+ &.MiniMode .CardImg{margin-bottom: 5px; width: 65px; height: 40px}
757
+
758
+ .CardImg {
759
+ height: 300px;
760
+ width: 100%;
761
+ background: url('https://breakthrough.org/wp-content/uploads/2018/10/default-placeholder-image.png');
762
+ background-repeat: no-repeat;
763
+ background-position: center;
764
+ background-size: auto;
765
+ &.CardImgFinished {
766
+ filter: grayscale(1);
767
+ }
768
+ &.Mobile{
769
+ width: 65px;
770
+ height: 40px;
771
+ display: inline-block;
772
+ }
773
+ }
774
+ .MobileRight{
775
+ display: inline-block;
776
+ line-height: 20px;
777
+ font-size: 11px;
778
+ padding: 2px 3px;
779
+ vertical-align: top;
780
+ width: calc(100% - 70px);
781
+ .Title{text-transform: capitalize; font-size: 14px; font-weight: 600}
782
+ }
783
+
784
+ .Status {
785
+ background: #000000;
786
+ display: flex;
787
+ justify-content: center;
788
+ align-items: center;
789
+ position: absolute;
790
+ top: 20px;
791
+ right: 20px;
792
+ min-height: 30px;
793
+ padding: 0 10px;
794
+ font-size: 12px;
795
+ text-transform: uppercase;
796
+ z-index: 1;
797
+ }
798
+
799
+ .Enrolled {
800
+ background: #2B2B5D;
801
+ color: #aaaabe;
802
+ display: flex;
803
+ justify-content: center;
804
+ align-items: center;
805
+ position: absolute;
806
+ top: 20px;
807
+ left: 20px;
808
+ min-height: 30px;
809
+ padding: 0 10px;
810
+ font-size: 12px;
811
+ text-transform: uppercase;
812
+ z-index: 1;
813
+ }
814
+ }
815
+ }
816
+
817
+ </style>