@everymatrix/general-player-login-form 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,529 +1,529 @@
1
- <svelte:options tag={null} />
2
-
3
- <script lang="ts">
4
- import { onMount } from "svelte";
5
- import { isMobile } from 'rvhelper';
6
-
7
- import '@everymatrix/general-player-sms-verification-form';
8
-
9
- // Native bridge
10
- import { isNative, call as callNative, registerEventListener as registerNativeEventListener } from 'js-native-bridge';
11
-
12
- import { _, addNewMessages, setLocale, setupI18n } from './i18n';
13
- import { LoginForm } from './translations';
14
-
15
- export let endpoint:string = '';
16
- export let imagedesktop:string = '';
17
- export let captchakey:string = '';
18
- export let lang:string = '';
19
- export let smsverification = 'false';
20
- export let simplepasswordvalidation:string = 'false';
21
-
22
- let playerId;
23
- let smsTokenId;
24
- let startSmsValidation = false;
25
- let smsTemplate: string = 'Please use this code {0} to activate your accout';
26
- let smsSendApiFailed = false;
27
- let number;
28
- let mobileView:boolean = false;
29
- let userAgent:string = window.navigator.userAgent;
30
- let userValue:string = '';
31
- let userPassword:string = '';
32
- // @TODO Typescript type model for loginFormData
33
- let loginFormData:any = {
34
- username: '',
35
- password: ''
36
- }
37
- let invalidName:boolean = false;
38
- let invalidPassword:boolean = false;
39
-
40
- let errorMessage:string = '';
41
-
42
- let isLoading:boolean = false;
43
- let passwordVisibilityToggle:HTMLElement;
44
- let isPasswordVisible:boolean = false;
45
- let isFormDataInvalid:boolean = true;
46
-
47
- // Native bridge
48
- let isOnNative:boolean = false;
49
- let waitingForCredentials:boolean = false;
50
-
51
- let nativeCredentials:any = {};
52
-
53
- let regexValidators = {
54
- user: /^(?!(?:.*\d){9})(?=(?:.*[a-zA-Z]){4})^[a-zA-Z\d]*$/,
55
- email: /^[^<>()*{}=/|?`~[\]\\,;:\%#^\s@\"$&!@]+@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z0-9]+\.)+[a-zA-Z]{2,}))$/i,
56
- password: /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,20}$/
57
- }
58
-
59
- setupI18n({ withLocale: 'en', translations: {}});
60
-
61
- Object.keys(LoginForm).forEach((item:any) => {
62
- addNewMessages(item, LoginForm[item]);
63
- });
64
-
65
- const doRecaptcha = ():Promise<string> => {
66
- return new Promise((resolve, reject) => {
67
- // @ts-ignore
68
- grecaptcha.ready(() => {
69
- // @ts-ignore
70
- grecaptcha.execute(captchakey, { action: "submit" })
71
- .then((token:string) => {
72
- resolve(token);
73
- });
74
- });
75
- });
76
- }
77
-
78
- const verifyTypeOfPassword = ():void => {
79
- if (simplepasswordvalidation == 'true') {
80
- regexValidators.password = /^(?!.* ).{8,20}$/;
81
- }
82
- }
83
-
84
- const showPassword = ():void => {
85
- isPasswordVisible = true;
86
- togglePasswordVisibility();
87
- }
88
-
89
- const hidePassword = ():void => {
90
- isPasswordVisible = false;
91
- togglePasswordVisibility();
92
- }
93
-
94
- const togglePasswordVisibility = ():void => {
95
- // @ts-ignore
96
- passwordVisibilityToggle.type = isPasswordVisible ? "text" : "password";
97
- }
98
-
99
- const switchToRegister = ():void => {
100
- window.postMessage({ type: "ToRegister" }, window.location.href);
101
- }
102
-
103
- const switchToForgotPassword = ():void => {
104
- window.postMessage({ type: "NavForgotPassword" }, window.location.href);
105
- }
106
-
107
- const submitLoginForm = (e):void => {
108
- e.preventDefault();
109
- doRecaptcha()
110
- .then((token:string) => {
111
- if (checkUserIdentifier(userValue) && checkUserPassword(userPassword)) {
112
- loginFormData = {
113
- username: userValue,
114
- password: userPassword,
115
- token: token
116
- };
117
- isLoading = true;
118
-
119
- window.postMessage({ type: "SubmitLoginForm", loginData: loginFormData }, window.location.href);
120
- }
121
- });
122
- }
123
-
124
- const checkUserIdentifier = (user:string):boolean => {
125
- if ((regexValidators.user.test(user) || regexValidators.email.test(user)) && user.length <= 100) {
126
- return true;
127
- } else {
128
- return false;
129
- }
130
- }
131
-
132
- const checkUserPassword = (password:string):boolean => {
133
- if (regexValidators.password.test(password)) {
134
- return true;
135
- } else {
136
- return false;
137
- }
138
- }
139
-
140
- const validateUserName = ():void => {
141
- invalidName = !checkUserIdentifier(userValue);
142
- isFormDataInvalid = (!invalidName && !invalidPassword && userPassword) ? false : true;
143
- }
144
-
145
- const validatePassword = ():void => {
146
- invalidPassword = !checkUserPassword(userPassword);
147
- isFormDataInvalid = (!invalidName && !invalidPassword && userValue) ? false : true;
148
- }
149
-
150
- const messageHandler = (e:MessageEvent):void => {
151
- if (e.data) {
152
- switch (e.data.type) {
153
- case 'ModalLoader':
154
- isLoading = false;
155
- break;
156
-
157
- case 'UserSessionID':
158
- isLoading = false;
159
- break;
160
-
161
- case 'HasError':
162
- errorMessage = e.data.error;
163
- isLoading = false;
164
- break;
165
-
166
- case 'SmsVerification':
167
- playerId = e.data.userid;
168
- number = e.data.number;
169
- startSmsValidation = e.data.startSmsValidation;
170
- sendSmsToken(number, playerId);
171
- break;
172
- case 'SmsHasBeenValidated':
173
- submitLoginForm();
174
- break;
175
- }
176
- }
177
- }
178
-
179
- const sendSmsToken = async (number, playerId) => {
180
- try {
181
- const res = await fetch(`${endpoint}/player/sms/token`,{
182
- method: 'POST',
183
- headers: {
184
- 'Content-Type': 'application/json',
185
- accept: 'application/json',
186
- },
187
- body: JSON.stringify(
188
- {
189
- userId: playerId,
190
- messageTemplate: smsTemplate,
191
- destination: number,
192
- }
193
- ),
194
- });
195
-
196
- const data = await res.json();
197
-
198
- if(res.ok) {
199
- smsTokenId = data.id;
200
- let smsMaxValidations = data.maxValidationAttempts;
201
- smsSendApiFailed = false;
202
- } else {
203
- smsSendApiFailed = true;
204
- throw new Error("Failed to fetch");
205
- }
206
- } catch(err) {
207
- smsSendApiFailed = true;
208
- console.error(err);
209
- }
210
- }
211
-
212
- const initialLoad = ():void => {
213
- setLocale(lang);
214
- }
215
-
216
- onMount(async () => {
217
- window.addEventListener("message", messageHandler, false);
218
- window.postMessage({ type: "LoginRegisterModalActive" }, window.location.href);
219
-
220
- isOnNative = !!isNative(userAgent);
221
- waitingForCredentials = isOnNative;
222
-
223
- if (isOnNative) {
224
- registerNativeEventListener(
225
- 'GET_CREDENTIALS',
226
- (credentials:any):void => {
227
- if (waitingForCredentials) {
228
- if (credentials) {
229
- const { username, password } = credentials;
230
-
231
- userValue = username;
232
- userPassword = password;
233
-
234
- submitLoginForm();
235
- } else {
236
- waitingForCredentials = false;
237
- }
238
- }
239
- }
240
- );
241
-
242
- const methodFound = callNative('GET_CREDENTIALS');
243
-
244
- if (!methodFound) {
245
- waitingForCredentials = false;
246
- }
247
- }
248
-
249
- mobileView = isMobile(userAgent);
250
-
251
- return () => {
252
- window.removeEventListener('message', messageHandler);
253
- }
254
- });
255
-
256
- $: endpoint && lang && initialLoad();
257
- $: simplepasswordvalidation && verifyTypeOfPassword();
258
- </script>
259
-
260
- <svelte:head>
261
- {#if captchakey}
262
- <script src="//www.google.com/recaptcha/api.js?render={captchakey}" async defer></script>
263
- {/if}
264
- </svelte:head>
265
-
266
- <div class="g-recaptcha" data-sitekey="{captchakey}" />
267
-
268
- {#if isLoading}
269
- <div class="ModalLoaderWrapper" part="ModalLoaderWrapper">
270
- <div class="ModalLoader" part="ModalLoader"></div>
271
- </div>
272
- {:else}
273
- <div class="FormContainer {mobileView ? 'FormMobileContainer' : ''}" part="FormContainer {mobileView ? 'FormMobileContainer' : ''}">
274
- <div class="FormLeftSide" part="FormLeftSide">
275
- {#if startSmsValidation}
276
- <general-player-sms-verification-form
277
- {endpoint}
278
- {number}
279
- playerid={playerId}
280
- tokenid={smsTokenId}>
281
- </general-player-sms-verification-form>
282
- {:else}
283
- <div class="FormHeader" part="FormHeader">
284
- <h4 class="FormHeaderTitle" part="FormHeaderTitle">{$_('loginForm.loginTitle')}</h4>
285
- <p class="FormHeaderSubtitle" part="FormHeaderSubtitle">{$_('loginForm.loginSubtitle')} <span class="FormRegisterCallToAction" on:click={() => switchToRegister()}>{$_('loginForm.loginSubtitleRegister')}</span></p>
286
- </div>
287
- {#if waitingForCredentials}
288
- <p>Waiting for credentials</p>
289
- {:else}
290
- <div class="FormContent" part="FormContent">
291
- <form id="signin" >
292
- <div class="UserContainer {invalidName ? 'InvalidField' : ''}" part="UserContainer {invalidName ? 'InvalidField' : ''}">
293
- <label for="username">{$_('loginForm.loginUsername')}:<span class="FormRequired" part="FormRequired">*</span></label>
294
- <input bind:value={userValue} on:keyup={validateUserName} type="text" id="email" name="email" autocomplete="username email" required/>
295
- {#if invalidName}
296
- <p class="InvalidInput" part="InvalidInput">{$_('loginForm.loginUsernameError')}</p>
297
- {/if}
298
- </div>
299
- <div class="PasswordContainer {invalidPassword ? 'InvalidField' : ''}" part="PasswordContainer {invalidPassword ? 'InvalidField' : ''}">
300
- <label for="current-password">{$_('loginForm.loginPassword')}:<span class="FormRequired" part="FormRequired">*</span></label>
301
- <input bind:value={userPassword} on:keyup={validatePassword} type="password" name="current-password" id="current-password" bind:this={passwordVisibilityToggle} autocomplete="current-password" aria-describedby="password-constraints" required/>
302
- {#if isPasswordVisible}
303
- <svg on:click={() => hidePassword()} class="TogglePasswordVisibility" part="TogglePasswordVisibility" xmlns="http://www.w3.org/2000/svg" width="18.844" height="12.887" viewBox="0 0 18.844 12.887"><defs><style>.a{fill:var(--emfe-w-color-contrast, #07072A);}</style></defs><g transform="translate(-110.856 -23.242)"><circle class="a" cx="0.05" cy="0.05" r="0.05" transform="translate(121.017 31.148)"/><g transform="translate(117.499 27.37)"><path class="a" d="M147.413,43.174a2.774,2.774,0,0,0-3.229-3.943Z" transform="translate(-142.164 -39.123)"/><path class="a" d="M137.031,43.1a2.778,2.778,0,0,0,3.447,4.209Z" transform="translate(-136.413 -42.068)"/></g><g transform="translate(110.856 24.899)"><path class="a" d="M122.538,42.061a7.043,7.043,0,0,1-2.325.53,10.373,10.373,0,0,1-4.393-1.482,36.509,36.509,0,0,1-3.873-2.391.13.13,0,0,1,0-.208,44.141,44.141,0,0,1,3.873-2.651c.394-.233.768-.437,1.13-.622l-.686-.838c-.322.167-.651.347-.99.55a37.989,37.989,0,0,0-3.977,2.729,1.21,1.21,0,0,0-.442.962,1.1,1.1,0,0,0,.494.936,34.416,34.416,0,0,0,3.977,2.469,11.468,11.468,0,0,0,4.886,1.611,8.427,8.427,0,0,0,3.039-.725Z" transform="translate(-110.856 -33.157)"/><path class="a" d="M149.119,34.14a45.875,45.875,0,0,0-4.055-2.729,20.541,20.541,0,0,0-2.547-1.248,5.6,5.6,0,0,0-4.79-.017l.7.856a5.254,5.254,0,0,1,1.672-.346,10.072,10.072,0,0,1,4.445,1.663,34.132,34.132,0,0,1,3.925,2.651.13.13,0,0,1,0,.208,40.2,40.2,0,0,1-3.925,2.391c-.179.092-.352.176-.525.26l.684.835c.1-.054.2-.1.309-.159a36.356,36.356,0,0,0,4.055-2.469,1.067,1.067,0,0,0,.52-.936A1.159,1.159,0,0,0,149.119,34.14Z" transform="translate(-130.743 -29.617)"/></g><rect class="a" width="0.972" height="15.861" rx="0.486" transform="translate(114.827 23.858) rotate(-39.315)"/></g></svg>
304
- {:else}
305
- <svg on:click={() => showPassword()} class="TogglePasswordVisibility" part="TogglePasswordVisibility" xmlns="http://www.w3.org/2000/svg" width="18.843" height="10.5" viewBox="0 0 18.843 10.5"><defs><style>.a{fill:var(--emfe-w-color-contrast, #07072A);}</style></defs><g transform="translate(-14.185 -27.832)"><path class="a" d="M23.541,38.332a11.467,11.467,0,0,1-4.886-1.611,34.413,34.413,0,0,1-3.976-2.469,1.1,1.1,0,0,1-.494-.936,1.21,1.21,0,0,1,.442-.962A37.986,37.986,0,0,1,18.6,29.625a16.06,16.06,0,0,1,2.521-1.248,6.862,6.862,0,0,1,2.417-.546,6.862,6.862,0,0,1,2.417.546,20.541,20.541,0,0,1,2.547,1.248,45.872,45.872,0,0,1,4.054,2.729,1.159,1.159,0,0,1,.468.962,1.067,1.067,0,0,1-.52.936,36.353,36.353,0,0,1-4.054,2.469A11.2,11.2,0,0,1,23.541,38.332Zm0-9.46a9.813,9.813,0,0,0-4.392,1.663,44.138,44.138,0,0,0-3.873,2.651.13.13,0,0,0,0,.208,36.5,36.5,0,0,0,3.873,2.391,10.372,10.372,0,0,0,4.392,1.481,11.051,11.051,0,0,0,4.444-1.481,40.2,40.2,0,0,0,3.925-2.391.13.13,0,0,0,0-.208h0a34.132,34.132,0,0,0-3.925-2.651A10.072,10.072,0,0,0,23.541,28.872Z" transform="translate(0)"/><circle class="a" cx="2.779" cy="2.779" r="2.779" transform="translate(20.827 30.303)"/></g></svg>
306
- {/if}
307
- {#if invalidPassword && simplepasswordvalidation !== 'true'}
308
- <p class="InvalidInput" part="InvalidInput">{$_('loginForm.loginPasswordError')}</p>
309
- {/if}
310
- {#if invalidPassword && simplepasswordvalidation === 'true'}
311
- <p class="InvalidInput" part="InvalidInput">{$_('loginForm.loginSimplePasswordError')}</p>
312
- {/if}
313
- </div>
314
- {#if errorMessage}
315
- <p class="ErrorMessage" part="ErrorMessage">{errorMessage}</p>
316
- {/if}
317
- <button class="SignInButton" part="SignInButton" on:click={(e) => submitLoginForm(e)} disabled={isFormDataInvalid} id="signin-button">{$_('loginForm.loginButton')}</button>
318
- <button class="ForgotPasswordButton" part="ForgotPasswordButton" on:click={() => switchToForgotPassword()}>{$_('loginForm.loginForgotPassword')}</button>
319
- </form>
320
- </div>
321
- {/if}
322
- {/if}
323
- </div>
324
- {#if !mobileView}
325
- <div class="FormRightSide" part="FormRightSide" style="background-image: url('{imagedesktop}')"></div>
326
- {/if}
327
- </div>
328
- {/if}
329
-
330
- <style lang="scss">
331
-
332
- :host {
333
- font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
334
- }
335
-
336
- .grecaptcha-badge { opacity:0;}
337
- .FormContainer {
338
- display: inline-flex;
339
- width: 100%;
340
- }
341
- .FormLeftSide, .FormRightSide {
342
- flex: 1 1 100%;
343
- padding: 50px;
344
- }
345
- .FormLeftSide {
346
- background: var(--emfe-w-color-gray-50, #F9F8F8);
347
- }
348
- .FormRightSide {
349
- background-size: cover;
350
- background-position: center;
351
- background-repeat: no-repeat;
352
- }
353
- .FormHeaderTitle {
354
- color: var(--emfe-w-color-black, #000000);
355
- font-size: 20px;
356
- font-weight: 300;
357
- padding: 0;
358
- text-transform: uppercase;
359
- margin: 0;
360
- }
361
- .PasswordContainer {
362
- position: relative;
363
- }
364
- .FormRequired {
365
- color: var(--emfe-w-color-secondary, #FD2839);
366
- }
367
- .FormHeaderSubtitle {
368
- color: var(--emfe-w-color-gray-300, #58586B);
369
- font-size: 14px;
370
- font-weight: 300;
371
- margin: 5px 0 0 0;
372
- }
373
- .FormRegisterCallToAction {
374
- color: var(--emfe-w-color-primary, #D0046C);
375
- font-size: 14px;
376
- font-weight: 400;
377
- text-decoration: none;
378
- cursor: pointer;
379
- }
380
- .FormContent {
381
- padding-top: 20px;
382
- }
383
- .UserContainer, .PasswordContainer, .CaptchaContainer {
384
- color: var(--emfe-w-color-gray-300, #58586B);
385
- display: flex;
386
- flex-direction: column;
387
- padding-bottom: 20px;
388
- position: relative;
389
- label {
390
- font-size: 14px;
391
- font-weight: 300;
392
- padding-bottom: 5px;
393
- }
394
- input {
395
- width: 100%;
396
- height: 44px;
397
- border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
398
- border-radius: 5px;
399
- box-sizing:border-box;
400
- padding: 5px 15px;
401
- font-size: 16px;
402
- line-height: 18px;
403
- }
404
- &.InvalidField {
405
- input {
406
- border: 1px solid var(--emfe-w-color-primary, #D0046C);
407
- background: var(--emfe-w-color-primary-50, #FBECF4);
408
- color: var(--emfe-w-color-primary, #D0046C);
409
- }
410
- }
411
- }
412
-
413
- .PasswordContainer input {
414
- padding: 5px 30px 5px 15px;
415
- }
416
-
417
- .TogglePasswordVisibility {
418
- height: 13px;
419
- position: absolute;
420
- right: 8px;
421
- bottom: 45px;
422
- &.InvalidToggle {
423
- path, circle, rect {
424
- fill: var(--emfe-w-color-primary, #D0046C);
425
- }
426
- }
427
- path, circle, rect {
428
- fill: var(--emfe-w-color-gray-300, #58586B);
429
- }
430
- }
431
- .SignInButton {
432
- color: var(--emfe-w-color-white, #FFFFFF);
433
- background: var(--emfe-w-color-primary, #D0046C);
434
- border: 1px solid var(--emfe-w-color-primary, #D0046C);
435
- border-radius: 5px;
436
- width: 100%;
437
- height: 60px;
438
- padding: 0;
439
- text-transform: uppercase;
440
- font-size: 18px;
441
- cursor: pointer;
442
- &[disabled] {
443
- background: var(--emfe-w-color-gray-100, #E6E6E6);
444
- border: 1px solid var(--emfe-w-color-gray-150, #828282);
445
- cursor: not-allowed;
446
- }
447
- }
448
- .ForgotPasswordButton {
449
- border: 0;
450
- background: transparent;
451
- font-size: 14px;
452
- font-weight: 300;
453
- color: var(--emfe-w-color-primary, #D0046C);
454
- margin-top: 15px;
455
- cursor: pointer;
456
- }
457
- .PasswordContainer, .UserContainer {
458
- padding-bottom: 30px;
459
- }
460
-
461
- .InvalidInput {
462
- color: var(--emfe-w-color-error, #FD2839);
463
- font-size: 10px;
464
- position: absolute;
465
- top: 55px;
466
- padding-top: 5px;
467
- line-height: 10px;
468
- }
469
- .ErrorMessage {
470
- margin: 0 0 15px 0;
471
- font-size: 12px;
472
- color: var(--emfe-w-color-error, #FD2839);
473
- }
474
- .FormMobileContainer {
475
- height:100%;
476
- .FormLeftSide {
477
- padding: 40px 20px;
478
- }
479
- .SignInButton,
480
- .UserContainer input,
481
- .PasswordContainer input,
482
- .CaptchaContainer {
483
- max-width: unset;
484
- }
485
- // .SuccessMessageContainer {
486
- // margin: 0;
487
- // height: 100%;
488
- // }
489
- }
490
-
491
- .ModalLoaderWrapper {
492
- display: flex;
493
- height: 100%;
494
- align-items: center;
495
- }
496
-
497
- .ModalLoader {
498
- display: block;
499
- width: 80px;
500
- height: 80px;
501
- margin: 0 auto
502
- }
503
- .ModalLoader:after {
504
- content: " ";
505
- display: block;
506
- width: 64px;
507
- height: 64px;
508
- margin: 8px;
509
- border-radius: 50%;
510
- border: 6px solid var(--emfe-w-color-primary, #D0046C);
511
- border-color: var(--emfe-w-color-primary, #D0046C) transparent var(--emfe-w-color-primary, #D0046C) transparent;
512
- animation: Loader 1.2s linear infinite;
513
- }
514
-
515
- /* MS Edge */
516
- input::-ms-reveal,
517
- input::-ms-clear {
518
- display: none;
519
- }
520
-
521
- @keyframes Loader {
522
- 0% {
523
- transform: rotate(0deg);
524
- }
525
- 100% {
526
- transform: rotate(360deg);
527
- }
528
- }
529
- </style>
1
+ <svelte:options tag={null} />
2
+
3
+ <script lang="ts">
4
+ import { onMount } from "svelte";
5
+ import { isMobile } from 'rvhelper';
6
+
7
+ import '@everymatrix/general-player-sms-verification-form';
8
+
9
+ // Native bridge
10
+ import { isNative, call as callNative, registerEventListener as registerNativeEventListener } from 'js-native-bridge';
11
+
12
+ import { _, addNewMessages, setLocale, setupI18n } from './i18n';
13
+ import { LoginForm } from './translations';
14
+
15
+ export let endpoint:string = '';
16
+ export let imagedesktop:string = '';
17
+ export let captchakey:string = '';
18
+ export let lang:string = '';
19
+ export let smsverification = 'false';
20
+ export let simplepasswordvalidation:string = 'false';
21
+
22
+ let playerId;
23
+ let smsTokenId;
24
+ let startSmsValidation = false;
25
+ let smsTemplate: string = 'Please use this code {0} to activate your accout';
26
+ let smsSendApiFailed = false;
27
+ let number;
28
+ let mobileView:boolean = false;
29
+ let userAgent:string = window.navigator.userAgent;
30
+ let userValue:string = '';
31
+ let userPassword:string = '';
32
+ // @TODO Typescript type model for loginFormData
33
+ let loginFormData:any = {
34
+ username: '',
35
+ password: ''
36
+ }
37
+ let invalidName:boolean = false;
38
+ let invalidPassword:boolean = false;
39
+
40
+ let errorMessage:string = '';
41
+
42
+ let isLoading:boolean = false;
43
+ let passwordVisibilityToggle:HTMLElement;
44
+ let isPasswordVisible:boolean = false;
45
+ let isFormDataInvalid:boolean = true;
46
+
47
+ // Native bridge
48
+ let isOnNative:boolean = false;
49
+ let waitingForCredentials:boolean = false;
50
+
51
+ let nativeCredentials:any = {};
52
+
53
+ let regexValidators = {
54
+ user: /^(?!(?:.*\d){9})(?=(?:.*[a-zA-Z]){4})^[a-zA-Z\d]*$/,
55
+ email: /^[^<>()*{}=/|?`~[\]\\,;:\%#^\s@\"$&!@]+@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z0-9]+\.)+[a-zA-Z]{2,}))$/i,
56
+ password: /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,20}$/
57
+ }
58
+
59
+ setupI18n({ withLocale: 'en', translations: {}});
60
+
61
+ Object.keys(LoginForm).forEach((item:any) => {
62
+ addNewMessages(item, LoginForm[item]);
63
+ });
64
+
65
+ const doRecaptcha = ():Promise<string> => {
66
+ return new Promise((resolve, reject) => {
67
+ // @ts-ignore
68
+ grecaptcha.ready(() => {
69
+ // @ts-ignore
70
+ grecaptcha.execute(captchakey, { action: "submit" })
71
+ .then((token:string) => {
72
+ resolve(token);
73
+ });
74
+ });
75
+ });
76
+ }
77
+
78
+ const verifyTypeOfPassword = ():void => {
79
+ if (simplepasswordvalidation == 'true') {
80
+ regexValidators.password = /^(?!.* ).{8,20}$/;
81
+ }
82
+ }
83
+
84
+ const showPassword = ():void => {
85
+ isPasswordVisible = true;
86
+ togglePasswordVisibility();
87
+ }
88
+
89
+ const hidePassword = ():void => {
90
+ isPasswordVisible = false;
91
+ togglePasswordVisibility();
92
+ }
93
+
94
+ const togglePasswordVisibility = ():void => {
95
+ // @ts-ignore
96
+ passwordVisibilityToggle.type = isPasswordVisible ? "text" : "password";
97
+ }
98
+
99
+ const switchToRegister = ():void => {
100
+ window.postMessage({ type: "ToRegister" }, window.location.href);
101
+ }
102
+
103
+ const switchToForgotPassword = ():void => {
104
+ window.postMessage({ type: "NavForgotPassword" }, window.location.href);
105
+ }
106
+
107
+ const submitLoginForm = (e):void => {
108
+ e.preventDefault();
109
+ doRecaptcha()
110
+ .then((token:string) => {
111
+ if (checkUserIdentifier(userValue) && checkUserPassword(userPassword)) {
112
+ loginFormData = {
113
+ username: userValue,
114
+ password: userPassword,
115
+ token: token
116
+ };
117
+ isLoading = true;
118
+
119
+ window.postMessage({ type: "SubmitLoginForm", loginData: loginFormData }, window.location.href);
120
+ }
121
+ });
122
+ }
123
+
124
+ const checkUserIdentifier = (user:string):boolean => {
125
+ if ((regexValidators.user.test(user) || regexValidators.email.test(user)) && user.length <= 100) {
126
+ return true;
127
+ } else {
128
+ return false;
129
+ }
130
+ }
131
+
132
+ const checkUserPassword = (password:string):boolean => {
133
+ if (regexValidators.password.test(password)) {
134
+ return true;
135
+ } else {
136
+ return false;
137
+ }
138
+ }
139
+
140
+ const validateUserName = ():void => {
141
+ invalidName = !checkUserIdentifier(userValue);
142
+ isFormDataInvalid = (!invalidName && !invalidPassword && userPassword) ? false : true;
143
+ }
144
+
145
+ const validatePassword = ():void => {
146
+ invalidPassword = !checkUserPassword(userPassword);
147
+ isFormDataInvalid = (!invalidName && !invalidPassword && userValue) ? false : true;
148
+ }
149
+
150
+ const messageHandler = (e:MessageEvent):void => {
151
+ if (e.data) {
152
+ switch (e.data.type) {
153
+ case 'ModalLoader':
154
+ isLoading = false;
155
+ break;
156
+
157
+ case 'UserSessionID':
158
+ isLoading = false;
159
+ break;
160
+
161
+ case 'HasError':
162
+ errorMessage = e.data.error;
163
+ isLoading = false;
164
+ break;
165
+
166
+ case 'SmsVerification':
167
+ playerId = e.data.userid;
168
+ number = e.data.number;
169
+ startSmsValidation = e.data.startSmsValidation;
170
+ sendSmsToken(number, playerId);
171
+ break;
172
+ case 'SmsHasBeenValidated':
173
+ submitLoginForm();
174
+ break;
175
+ }
176
+ }
177
+ }
178
+
179
+ const sendSmsToken = async (number, playerId) => {
180
+ try {
181
+ const res = await fetch(`${endpoint}/player/sms/token`,{
182
+ method: 'POST',
183
+ headers: {
184
+ 'Content-Type': 'application/json',
185
+ accept: 'application/json',
186
+ },
187
+ body: JSON.stringify(
188
+ {
189
+ userId: playerId,
190
+ messageTemplate: smsTemplate,
191
+ destination: number,
192
+ }
193
+ ),
194
+ });
195
+
196
+ const data = await res.json();
197
+
198
+ if(res.ok) {
199
+ smsTokenId = data.id;
200
+ let smsMaxValidations = data.maxValidationAttempts;
201
+ smsSendApiFailed = false;
202
+ } else {
203
+ smsSendApiFailed = true;
204
+ throw new Error("Failed to fetch");
205
+ }
206
+ } catch(err) {
207
+ smsSendApiFailed = true;
208
+ console.error(err);
209
+ }
210
+ }
211
+
212
+ const initialLoad = ():void => {
213
+ setLocale(lang);
214
+ }
215
+
216
+ onMount(async () => {
217
+ window.addEventListener("message", messageHandler, false);
218
+ window.postMessage({ type: "LoginRegisterModalActive" }, window.location.href);
219
+
220
+ isOnNative = !!isNative(userAgent);
221
+ waitingForCredentials = isOnNative;
222
+
223
+ if (isOnNative) {
224
+ registerNativeEventListener(
225
+ 'GET_CREDENTIALS',
226
+ (credentials:any):void => {
227
+ if (waitingForCredentials) {
228
+ if (credentials) {
229
+ const { username, password } = credentials;
230
+
231
+ userValue = username;
232
+ userPassword = password;
233
+
234
+ submitLoginForm();
235
+ } else {
236
+ waitingForCredentials = false;
237
+ }
238
+ }
239
+ }
240
+ );
241
+
242
+ const methodFound = callNative('GET_CREDENTIALS');
243
+
244
+ if (!methodFound) {
245
+ waitingForCredentials = false;
246
+ }
247
+ }
248
+
249
+ mobileView = isMobile(userAgent);
250
+
251
+ return () => {
252
+ window.removeEventListener('message', messageHandler);
253
+ }
254
+ });
255
+
256
+ $: endpoint && lang && initialLoad();
257
+ $: simplepasswordvalidation && verifyTypeOfPassword();
258
+ </script>
259
+
260
+ <svelte:head>
261
+ {#if captchakey}
262
+ <script src="//www.google.com/recaptcha/api.js?render={captchakey}" async defer></script>
263
+ {/if}
264
+ </svelte:head>
265
+
266
+ <div class="g-recaptcha" data-sitekey="{captchakey}" />
267
+
268
+ {#if isLoading}
269
+ <div class="ModalLoaderWrapper" part="ModalLoaderWrapper">
270
+ <div class="ModalLoader" part="ModalLoader"></div>
271
+ </div>
272
+ {:else}
273
+ <div class="FormContainer {mobileView ? 'FormMobileContainer' : ''}" part="FormContainer {mobileView ? 'FormMobileContainer' : ''}">
274
+ <div class="FormLeftSide" part="FormLeftSide">
275
+ {#if startSmsValidation}
276
+ <general-player-sms-verification-form
277
+ {endpoint}
278
+ {number}
279
+ playerid={playerId}
280
+ tokenid={smsTokenId}>
281
+ </general-player-sms-verification-form>
282
+ {:else}
283
+ <div class="FormHeader" part="FormHeader">
284
+ <h4 class="FormHeaderTitle" part="FormHeaderTitle">{$_('loginForm.loginTitle')}</h4>
285
+ <p class="FormHeaderSubtitle" part="FormHeaderSubtitle">{$_('loginForm.loginSubtitle')} <span class="FormRegisterCallToAction" on:click={() => switchToRegister()}>{$_('loginForm.loginSubtitleRegister')}</span></p>
286
+ </div>
287
+ {#if waitingForCredentials}
288
+ <p>Waiting for credentials</p>
289
+ {:else}
290
+ <div class="FormContent" part="FormContent">
291
+ <form id="signin" >
292
+ <div class="UserContainer {invalidName ? 'InvalidField' : ''}" part="UserContainer {invalidName ? 'InvalidField' : ''}">
293
+ <label for="username">{$_('loginForm.loginUsername')}:<span class="FormRequired" part="FormRequired">*</span></label>
294
+ <input bind:value={userValue} on:keyup={validateUserName} type="text" id="email" name="email" autocomplete="username email" required/>
295
+ {#if invalidName}
296
+ <p class="InvalidInput" part="InvalidInput">{$_('loginForm.loginUsernameError')}</p>
297
+ {/if}
298
+ </div>
299
+ <div class="PasswordContainer {invalidPassword ? 'InvalidField' : ''}" part="PasswordContainer {invalidPassword ? 'InvalidField' : ''}">
300
+ <label for="current-password">{$_('loginForm.loginPassword')}:<span class="FormRequired" part="FormRequired">*</span></label>
301
+ <input bind:value={userPassword} on:keyup={validatePassword} type="password" name="current-password" id="current-password" bind:this={passwordVisibilityToggle} autocomplete="current-password" aria-describedby="password-constraints" required/>
302
+ {#if isPasswordVisible}
303
+ <svg on:click={() => hidePassword()} class="TogglePasswordVisibility" part="TogglePasswordVisibility" xmlns="http://www.w3.org/2000/svg" width="18.844" height="12.887" viewBox="0 0 18.844 12.887"><defs><style>.a{fill:var(--emfe-w-color-contrast, #07072A);}</style></defs><g transform="translate(-110.856 -23.242)"><circle class="a" cx="0.05" cy="0.05" r="0.05" transform="translate(121.017 31.148)"/><g transform="translate(117.499 27.37)"><path class="a" d="M147.413,43.174a2.774,2.774,0,0,0-3.229-3.943Z" transform="translate(-142.164 -39.123)"/><path class="a" d="M137.031,43.1a2.778,2.778,0,0,0,3.447,4.209Z" transform="translate(-136.413 -42.068)"/></g><g transform="translate(110.856 24.899)"><path class="a" d="M122.538,42.061a7.043,7.043,0,0,1-2.325.53,10.373,10.373,0,0,1-4.393-1.482,36.509,36.509,0,0,1-3.873-2.391.13.13,0,0,1,0-.208,44.141,44.141,0,0,1,3.873-2.651c.394-.233.768-.437,1.13-.622l-.686-.838c-.322.167-.651.347-.99.55a37.989,37.989,0,0,0-3.977,2.729,1.21,1.21,0,0,0-.442.962,1.1,1.1,0,0,0,.494.936,34.416,34.416,0,0,0,3.977,2.469,11.468,11.468,0,0,0,4.886,1.611,8.427,8.427,0,0,0,3.039-.725Z" transform="translate(-110.856 -33.157)"/><path class="a" d="M149.119,34.14a45.875,45.875,0,0,0-4.055-2.729,20.541,20.541,0,0,0-2.547-1.248,5.6,5.6,0,0,0-4.79-.017l.7.856a5.254,5.254,0,0,1,1.672-.346,10.072,10.072,0,0,1,4.445,1.663,34.132,34.132,0,0,1,3.925,2.651.13.13,0,0,1,0,.208,40.2,40.2,0,0,1-3.925,2.391c-.179.092-.352.176-.525.26l.684.835c.1-.054.2-.1.309-.159a36.356,36.356,0,0,0,4.055-2.469,1.067,1.067,0,0,0,.52-.936A1.159,1.159,0,0,0,149.119,34.14Z" transform="translate(-130.743 -29.617)"/></g><rect class="a" width="0.972" height="15.861" rx="0.486" transform="translate(114.827 23.858) rotate(-39.315)"/></g></svg>
304
+ {:else}
305
+ <svg on:click={() => showPassword()} class="TogglePasswordVisibility" part="TogglePasswordVisibility" xmlns="http://www.w3.org/2000/svg" width="18.843" height="10.5" viewBox="0 0 18.843 10.5"><defs><style>.a{fill:var(--emfe-w-color-contrast, #07072A);}</style></defs><g transform="translate(-14.185 -27.832)"><path class="a" d="M23.541,38.332a11.467,11.467,0,0,1-4.886-1.611,34.413,34.413,0,0,1-3.976-2.469,1.1,1.1,0,0,1-.494-.936,1.21,1.21,0,0,1,.442-.962A37.986,37.986,0,0,1,18.6,29.625a16.06,16.06,0,0,1,2.521-1.248,6.862,6.862,0,0,1,2.417-.546,6.862,6.862,0,0,1,2.417.546,20.541,20.541,0,0,1,2.547,1.248,45.872,45.872,0,0,1,4.054,2.729,1.159,1.159,0,0,1,.468.962,1.067,1.067,0,0,1-.52.936,36.353,36.353,0,0,1-4.054,2.469A11.2,11.2,0,0,1,23.541,38.332Zm0-9.46a9.813,9.813,0,0,0-4.392,1.663,44.138,44.138,0,0,0-3.873,2.651.13.13,0,0,0,0,.208,36.5,36.5,0,0,0,3.873,2.391,10.372,10.372,0,0,0,4.392,1.481,11.051,11.051,0,0,0,4.444-1.481,40.2,40.2,0,0,0,3.925-2.391.13.13,0,0,0,0-.208h0a34.132,34.132,0,0,0-3.925-2.651A10.072,10.072,0,0,0,23.541,28.872Z" transform="translate(0)"/><circle class="a" cx="2.779" cy="2.779" r="2.779" transform="translate(20.827 30.303)"/></g></svg>
306
+ {/if}
307
+ {#if invalidPassword && simplepasswordvalidation !== 'true'}
308
+ <p class="InvalidInput" part="InvalidInput">{$_('loginForm.loginPasswordError')}</p>
309
+ {/if}
310
+ {#if invalidPassword && simplepasswordvalidation === 'true'}
311
+ <p class="InvalidInput" part="InvalidInput">{$_('loginForm.loginSimplePasswordError')}</p>
312
+ {/if}
313
+ </div>
314
+ {#if errorMessage}
315
+ <p class="ErrorMessage" part="ErrorMessage">{errorMessage}</p>
316
+ {/if}
317
+ <button class="SignInButton" part="SignInButton" on:click={(e) => submitLoginForm(e)} disabled={isFormDataInvalid} id="signin-button">{$_('loginForm.loginButton')}</button>
318
+ <button class="ForgotPasswordButton" part="ForgotPasswordButton" on:click={() => switchToForgotPassword()}>{$_('loginForm.loginForgotPassword')}</button>
319
+ </form>
320
+ </div>
321
+ {/if}
322
+ {/if}
323
+ </div>
324
+ {#if !mobileView}
325
+ <div class="FormRightSide" part="FormRightSide" style="background-image: url('{imagedesktop}')"></div>
326
+ {/if}
327
+ </div>
328
+ {/if}
329
+
330
+ <style lang="scss">
331
+
332
+ :host {
333
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
334
+ }
335
+
336
+ .grecaptcha-badge { opacity:0;}
337
+ .FormContainer {
338
+ display: inline-flex;
339
+ width: 100%;
340
+ }
341
+ .FormLeftSide, .FormRightSide {
342
+ flex: 1 1 100%;
343
+ padding: 50px;
344
+ }
345
+ .FormLeftSide {
346
+ background: var(--emfe-w-color-gray-50, #F9F8F8);
347
+ }
348
+ .FormRightSide {
349
+ background-size: cover;
350
+ background-position: center;
351
+ background-repeat: no-repeat;
352
+ }
353
+ .FormHeaderTitle {
354
+ color: var(--emfe-w-color-black, #000000);
355
+ font-size: 20px;
356
+ font-weight: 300;
357
+ padding: 0;
358
+ text-transform: uppercase;
359
+ margin: 0;
360
+ }
361
+ .PasswordContainer {
362
+ position: relative;
363
+ }
364
+ .FormRequired {
365
+ color: var(--emfe-w-color-secondary, #FD2839);
366
+ }
367
+ .FormHeaderSubtitle {
368
+ color: var(--emfe-w-color-gray-300, #58586B);
369
+ font-size: 14px;
370
+ font-weight: 300;
371
+ margin: 5px 0 0 0;
372
+ }
373
+ .FormRegisterCallToAction {
374
+ color: var(--emfe-w-color-primary, #D0046C);
375
+ font-size: 14px;
376
+ font-weight: 400;
377
+ text-decoration: none;
378
+ cursor: pointer;
379
+ }
380
+ .FormContent {
381
+ padding-top: 20px;
382
+ }
383
+ .UserContainer, .PasswordContainer, .CaptchaContainer {
384
+ color: var(--emfe-w-color-gray-300, #58586B);
385
+ display: flex;
386
+ flex-direction: column;
387
+ padding-bottom: 20px;
388
+ position: relative;
389
+ label {
390
+ font-size: 14px;
391
+ font-weight: 300;
392
+ padding-bottom: 5px;
393
+ }
394
+ input {
395
+ width: 100%;
396
+ height: 44px;
397
+ border: 1px solid var(--emfe-w-color-gray-100, #E6E6E6);
398
+ border-radius: 5px;
399
+ box-sizing:border-box;
400
+ padding: 5px 15px;
401
+ font-size: 16px;
402
+ line-height: 18px;
403
+ }
404
+ &.InvalidField {
405
+ input {
406
+ border: 1px solid var(--emfe-w-color-primary, #D0046C);
407
+ background: var(--emfe-w-color-primary-50, #FBECF4);
408
+ color: var(--emfe-w-color-primary, #D0046C);
409
+ }
410
+ }
411
+ }
412
+
413
+ .PasswordContainer input {
414
+ padding: 5px 30px 5px 15px;
415
+ }
416
+
417
+ .TogglePasswordVisibility {
418
+ height: 13px;
419
+ position: absolute;
420
+ right: 8px;
421
+ bottom: 45px;
422
+ &.InvalidToggle {
423
+ path, circle, rect {
424
+ fill: var(--emfe-w-color-primary, #D0046C);
425
+ }
426
+ }
427
+ path, circle, rect {
428
+ fill: var(--emfe-w-color-gray-300, #58586B);
429
+ }
430
+ }
431
+ .SignInButton {
432
+ color: var(--emfe-w-color-white, #FFFFFF);
433
+ background: var(--emfe-w-color-primary, #D0046C);
434
+ border: 1px solid var(--emfe-w-color-primary, #D0046C);
435
+ border-radius: 5px;
436
+ width: 100%;
437
+ height: 60px;
438
+ padding: 0;
439
+ text-transform: uppercase;
440
+ font-size: 18px;
441
+ cursor: pointer;
442
+ &[disabled] {
443
+ background: var(--emfe-w-color-gray-100, #E6E6E6);
444
+ border: 1px solid var(--emfe-w-color-gray-150, #828282);
445
+ cursor: not-allowed;
446
+ }
447
+ }
448
+ .ForgotPasswordButton {
449
+ border: 0;
450
+ background: transparent;
451
+ font-size: 14px;
452
+ font-weight: 300;
453
+ color: var(--emfe-w-color-primary, #D0046C);
454
+ margin-top: 15px;
455
+ cursor: pointer;
456
+ }
457
+ .PasswordContainer, .UserContainer {
458
+ padding-bottom: 30px;
459
+ }
460
+
461
+ .InvalidInput {
462
+ color: var(--emfe-w-color-error, #FD2839);
463
+ font-size: 10px;
464
+ position: absolute;
465
+ top: 55px;
466
+ padding-top: 5px;
467
+ line-height: 10px;
468
+ }
469
+ .ErrorMessage {
470
+ margin: 0 0 15px 0;
471
+ font-size: 12px;
472
+ color: var(--emfe-w-color-error, #FD2839);
473
+ }
474
+ .FormMobileContainer {
475
+ height:100%;
476
+ .FormLeftSide {
477
+ padding: 40px 20px;
478
+ }
479
+ .SignInButton,
480
+ .UserContainer input,
481
+ .PasswordContainer input,
482
+ .CaptchaContainer {
483
+ max-width: unset;
484
+ }
485
+ // .SuccessMessageContainer {
486
+ // margin: 0;
487
+ // height: 100%;
488
+ // }
489
+ }
490
+
491
+ .ModalLoaderWrapper {
492
+ display: flex;
493
+ height: 100%;
494
+ align-items: center;
495
+ }
496
+
497
+ .ModalLoader {
498
+ display: block;
499
+ width: 80px;
500
+ height: 80px;
501
+ margin: 0 auto
502
+ }
503
+ .ModalLoader:after {
504
+ content: " ";
505
+ display: block;
506
+ width: 64px;
507
+ height: 64px;
508
+ margin: 8px;
509
+ border-radius: 50%;
510
+ border: 6px solid var(--emfe-w-color-primary, #D0046C);
511
+ border-color: var(--emfe-w-color-primary, #D0046C) transparent var(--emfe-w-color-primary, #D0046C) transparent;
512
+ animation: Loader 1.2s linear infinite;
513
+ }
514
+
515
+ /* MS Edge */
516
+ input::-ms-reveal,
517
+ input::-ms-clear {
518
+ display: none;
519
+ }
520
+
521
+ @keyframes Loader {
522
+ 0% {
523
+ transform: rotate(0deg);
524
+ }
525
+ 100% {
526
+ transform: rotate(360deg);
527
+ }
528
+ }
529
+ </style>