@xsolla/payment-client-core 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/esm2020/lib/core/credit-card/credit-card-settings.interface.mjs +2 -0
  2. package/esm2020/lib/core/credit-card/credit-card-types.enum.mjs +20 -0
  3. package/esm2020/lib/core/credit-card/credit-card.interface.mjs +2 -0
  4. package/esm2020/lib/core/credit-card/credit-card.service.mjs +41 -0
  5. package/esm2020/lib/core/credit-card/credit-cards-map.const.mjs +36 -0
  6. package/esm2020/lib/core/credit-card/default-mask.const.mjs +2 -0
  7. package/esm2020/lib/core/credit-card/four-block-mask.const.mjs +2 -0
  8. package/esm2020/lib/core/credit-card/ordered-cards-settings.const.mjs +45 -0
  9. package/esm2020/lib/core/credit-card/types/american-express.mjs +13 -0
  10. package/esm2020/lib/core/credit-card/types/aura.mjs +15 -0
  11. package/esm2020/lib/core/credit-card/types/china-union-pay.mjs +12 -0
  12. package/esm2020/lib/core/credit-card/types/dankort.mjs +15 -0
  13. package/esm2020/lib/core/credit-card/types/default-card.mjs +13 -0
  14. package/esm2020/lib/core/credit-card/types/diners-clubs.mjs +13 -0
  15. package/esm2020/lib/core/credit-card/types/discover.mjs +13 -0
  16. package/esm2020/lib/core/credit-card/types/elo.mjs +13 -0
  17. package/esm2020/lib/core/credit-card/types/hipercard.mjs +13 -0
  18. package/esm2020/lib/core/credit-card/types/jcb.mjs +13 -0
  19. package/esm2020/lib/core/credit-card/types/maestro.mjs +14 -0
  20. package/esm2020/lib/core/credit-card/types/mastercard.mjs +16 -0
  21. package/esm2020/lib/core/credit-card/types/mir.mjs +15 -0
  22. package/esm2020/lib/core/credit-card/types/naranja.mjs +15 -0
  23. package/esm2020/lib/core/credit-card/types/postepay.mjs +13 -0
  24. package/esm2020/lib/core/credit-card/types/visa.mjs +13 -0
  25. package/esm2020/lib/core/payment/actions/next-action.interface.mjs +1 -1
  26. package/esm2020/lib/core/payment/actions/next-actions.mjs +1 -3
  27. package/esm2020/lib/core/payment/actions/show-fields/show-fields.action.token.mjs +3 -2
  28. package/esm2020/lib/core/payment/credit-card-state/credit-card-state.interface.mjs +2 -0
  29. package/esm2020/lib/core/payment/credit-card-state/credit-card-state.service.mjs +14 -0
  30. package/esm2020/lib/core/payment/form/controls/card-number-control.config.mjs +10 -0
  31. package/esm2020/lib/core/payment/form/converters/card-number.converter.mjs +45 -0
  32. package/esm2020/lib/core/payment/form/converters/converter.abstract.mjs +8 -6
  33. package/esm2020/lib/core/payment/form/converters/converters-map.mjs +3 -1
  34. package/esm2020/lib/core/payment/form/converters/email.converter.mjs +3 -3
  35. package/esm2020/lib/core/payment/form/converters/zip.converter.mjs +4 -5
  36. package/esm2020/lib/core/payment/form/field-status.interface.mjs +2 -0
  37. package/esm2020/lib/core/payment/form/form-fields-status.interface.mjs +2 -0
  38. package/esm2020/lib/core/payment/form/form.module.mjs +8 -4
  39. package/esm2020/lib/core/payment/form/input-event.enum.mjs +6 -0
  40. package/esm2020/lib/core/payment/form/validators/async-validator-fn.type.mjs +2 -0
  41. package/esm2020/lib/core/payment/form/validators/convert.function.mjs +6 -14
  42. package/esm2020/lib/core/payment/form/validators/credit-card-min-length.validator.mjs +32 -0
  43. package/esm2020/lib/core/payment/form/validators/email-validator.mjs +3 -4
  44. package/esm2020/lib/core/payment/form/validators/is-empty-input-value.function.mjs +4 -0
  45. package/esm2020/lib/core/payment/form/validators/luhn-formula-validator/luhn-formula.validator.mjs +40 -0
  46. package/esm2020/lib/core/payment/form/validators/required-validator.mjs +3 -4
  47. package/esm2020/lib/core/payment/form/validators/validation-error.interface.mjs +1 -1
  48. package/esm2020/lib/core/payment/form/validators/validators.module.mjs +18 -0
  49. package/esm2020/lib/core/payment/payment.interface.mjs +1 -1
  50. package/esm2020/lib/core/payment/payment.service.mjs +57 -46
  51. package/esm2020/lib/core/payment/sync/field-async-validation.interface.mjs +2 -0
  52. package/esm2020/lib/core/payment/sync/sync-response.class.mjs +7 -4
  53. package/esm2020/lib/core/payment/sync/sync.service.mjs +14 -11
  54. package/esm2020/lib/core/payment/xps-response.interface.mjs +1 -1
  55. package/esm2020/lib/core/type-guards/is-string.function.mjs +4 -0
  56. package/esm2020/lib/core-library.service.mjs +20 -7
  57. package/fesm2015/xsolla-payment-client-core.mjs +559 -120
  58. package/fesm2015/xsolla-payment-client-core.mjs.map +1 -1
  59. package/fesm2020/xsolla-payment-client-core.mjs +558 -119
  60. package/fesm2020/xsolla-payment-client-core.mjs.map +1 -1
  61. package/lib/core/credit-card/credit-card-settings.interface.d.ts +10 -0
  62. package/lib/core/credit-card/credit-card-types.enum.d.ts +18 -0
  63. package/lib/core/credit-card/credit-card.interface.d.ts +9 -0
  64. package/lib/core/credit-card/credit-card.service.d.ts +11 -0
  65. package/lib/core/credit-card/credit-cards-map.const.d.ts +5 -0
  66. package/lib/core/credit-card/default-mask.const.d.ts +1 -0
  67. package/lib/core/credit-card/four-block-mask.const.d.ts +1 -0
  68. package/lib/core/credit-card/ordered-cards-settings.const.d.ts +12 -0
  69. package/lib/core/credit-card/types/american-express.d.ts +2 -0
  70. package/lib/core/credit-card/types/aura.d.ts +2 -0
  71. package/lib/core/credit-card/types/china-union-pay.d.ts +2 -0
  72. package/lib/core/credit-card/types/dankort.d.ts +2 -0
  73. package/lib/core/credit-card/types/default-card.d.ts +2 -0
  74. package/lib/core/credit-card/types/diners-clubs.d.ts +2 -0
  75. package/lib/core/credit-card/types/discover.d.ts +2 -0
  76. package/lib/core/credit-card/types/elo.d.ts +2 -0
  77. package/lib/core/credit-card/types/hipercard.d.ts +2 -0
  78. package/lib/core/credit-card/types/jcb.d.ts +2 -0
  79. package/lib/core/credit-card/types/maestro.d.ts +2 -0
  80. package/lib/core/credit-card/types/mastercard.d.ts +2 -0
  81. package/lib/core/credit-card/types/mir.d.ts +2 -0
  82. package/lib/core/credit-card/types/naranja.d.ts +2 -0
  83. package/lib/core/credit-card/types/postepay.d.ts +2 -0
  84. package/lib/core/credit-card/types/visa.d.ts +2 -0
  85. package/lib/core/payment/actions/next-action.interface.d.ts +1 -2
  86. package/lib/core/payment/credit-card-state/credit-card-state.interface.d.ts +3 -0
  87. package/lib/core/payment/credit-card-state/credit-card-state.service.d.ts +7 -0
  88. package/lib/core/payment/form/controls/card-number-control.config.d.ts +11 -0
  89. package/lib/core/payment/form/converters/card-number.converter.d.ts +19 -0
  90. package/lib/core/payment/form/converters/converter.abstract.d.ts +4 -1
  91. package/lib/core/payment/form/converters/email.converter.d.ts +1 -1
  92. package/lib/core/payment/form/field-status.interface.d.ts +7 -0
  93. package/lib/core/payment/form/form-fields-status.interface.d.ts +4 -0
  94. package/lib/core/payment/form/form.module.d.ts +2 -1
  95. package/lib/core/payment/form/validators/async-validator-fn.type.d.ts +4 -0
  96. package/lib/core/payment/form/validators/convert.function.d.ts +1 -1
  97. package/lib/core/payment/form/validators/credit-card-min-length.validator.d.ts +12 -0
  98. package/lib/core/payment/form/validators/email-validator.d.ts +1 -1
  99. package/lib/core/payment/form/validators/is-empty-input-value.function.d.ts +1 -0
  100. package/lib/core/payment/form/validators/luhn-formula-validator/luhn-formula.validator.d.ts +6 -0
  101. package/lib/core/payment/form/validators/required-validator.d.ts +1 -1
  102. package/lib/core/payment/form/validators/validation-error.interface.d.ts +0 -1
  103. package/lib/core/payment/form/validators/validators.module.d.ts +7 -0
  104. package/lib/core/payment/payment.interface.d.ts +3 -1
  105. package/lib/core/payment/payment.service.d.ts +12 -4
  106. package/lib/core/payment/sync/field-async-validation.interface.d.ts +7 -0
  107. package/lib/core/payment/sync/sync-response.class.d.ts +2 -4
  108. package/lib/core/payment/sync/sync.service.d.ts +4 -0
  109. package/lib/core/payment/xps-response.interface.d.ts +1 -0
  110. package/lib/core/type-guards/is-string.function.d.ts +1 -0
  111. package/lib/core-library.service.d.ts +10 -1
  112. package/package.json +1 -1
  113. package/xsolla-payment-client-core-0.1.4.tgz +0 -0
  114. package/esm2020/lib/core/payment/actions/show-field-state/show-field-state.action.class.mjs +0 -12
  115. package/esm2020/lib/core/payment/actions/show-field-state/show-field-state.action.token.mjs +0 -13
  116. package/esm2020/lib/core/payment/actions/show-field-state/show-field-state.action.type.mjs +0 -2
  117. package/esm2020/lib/core/payment/form/input-events.enum.mjs +0 -6
  118. package/esm2020/lib/core/payment/form/validators/errors-codes.enum.mjs +0 -8
  119. package/esm2020/lib/core/payment/show-field-state.interface.mjs +0 -2
  120. package/lib/core/payment/actions/show-field-state/show-field-state.action.class.d.ts +0 -8
  121. package/lib/core/payment/actions/show-field-state/show-field-state.action.token.d.ts +0 -4
  122. package/lib/core/payment/actions/show-field-state/show-field-state.action.type.d.ts +0 -11
  123. package/lib/core/payment/form/validators/errors-codes.enum.d.ts +0 -6
  124. package/lib/core/payment/show-field-state.interface.d.ts +0 -8
  125. package/xsolla-payment-client-core-0.1.2.tgz +0 -0
  126. /package/lib/core/payment/form/{input-events.enum.d.ts → input-event.enum.d.ts} +0 -0
@@ -1,11 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Injectable, Inject, isDevMode, NgModule } from '@angular/core';
3
- import { firstValueFrom, lastValueFrom, map, Subject, tap, BehaviorSubject, filter as filter$1, takeUntil, skip, distinctUntilChanged, throwError } from 'rxjs';
3
+ import { firstValueFrom, lastValueFrom, map, Subject, tap, BehaviorSubject, filter as filter$1, takeUntil, skip, throwError } from 'rxjs';
4
4
  import * as i1 from '@angular/common/http';
5
5
  import { HttpParams, HttpHeaders, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
6
6
  import { UntypedFormGroup, Validators, UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
7
7
  import { filter, map as map$1, catchError } from 'rxjs/operators';
8
8
  import * as i1$1 from '@angular/router';
9
+ import { CommonModule } from '@angular/common';
9
10
 
10
11
  const masksFunctionsMap = {
11
12
  zip: () => {
@@ -573,18 +574,6 @@ const isSubmitResponse = (value) => {
573
574
  return value instanceof SubmitResponse;
574
575
  };
575
576
 
576
- class ShowFieldStateAction {
577
- constructor(control) {
578
- this.type = 'show_field_state';
579
- this.data = {
580
- fieldName: control.fieldName,
581
- fieldState: control.fieldState,
582
- error: control.error,
583
- isFocused: control.isFocused,
584
- };
585
- }
586
- }
587
-
588
577
  var InputEventName;
589
578
  (function (InputEventName) {
590
579
  InputEventName["blur"] = "blur";
@@ -671,7 +660,8 @@ const showFieldsActionFactoryProvider = {
671
660
  useValue: {
672
661
  factory: (...args) => new ShowFieldsAction(...args),
673
662
  isSuitable: (response) => {
674
- return response.currentCommand === XpsCommand.check;
663
+ return (response.currentCommand === XpsCommand.check ||
664
+ response.currentCommand === XpsCommand.form);
675
665
  },
676
666
  },
677
667
  };
@@ -769,17 +759,6 @@ const showErrorsActionFactoryProvider = {
769
759
  },
770
760
  };
771
761
 
772
- const showFieldStateActionFactoryToken = new InjectionToken('ShowFieldStateAction');
773
- const showFieldStateActionFactoryProvider = {
774
- provide: showFieldStateActionFactoryToken,
775
- useValue: {
776
- factory: (...args) => new ShowFieldStateAction(...args),
777
- isSuitable: () => {
778
- return true;
779
- },
780
- },
781
- };
782
-
783
762
  const nextActionsToken = new InjectionToken('Action');
784
763
  const nextActions = [
785
764
  showFieldsActionFactoryProvider,
@@ -789,7 +768,6 @@ const nextActions = [
789
768
  const flowUpdateNextActions = [
790
769
  statusUpdatedActionFactoryProvider,
791
770
  showErrorsActionFactoryProvider,
792
- showFieldStateActionFactoryProvider,
793
771
  ];
794
772
 
795
773
  class NextActionService {
@@ -1217,11 +1195,14 @@ const syncRequestFactoryProvider = {
1217
1195
 
1218
1196
  class SyncResponse {
1219
1197
  constructor(changedField, response) {
1198
+ this.error = null;
1220
1199
  const fieldError = response?.errors?.find((error) => error.element_name === changedField.name);
1221
1200
  if (fieldError) {
1222
- this.rewritableError = {
1223
- code: fieldError.code,
1224
- message: fieldError.message,
1201
+ this.error = {
1202
+ asyncError: {
1203
+ code: fieldError.code,
1204
+ message: fieldError.message,
1205
+ },
1225
1206
  };
1226
1207
  }
1227
1208
  this.fields = Object.keys(response.form).map((key) => response.form[key]);
@@ -1247,6 +1228,10 @@ class SyncService extends EmitDataService {
1247
1228
  this.prevFieldSyncStates = {};
1248
1229
  this.form = new UntypedFormGroup({});
1249
1230
  this.fields = [];
1231
+ this.fieldAsyncValidation = new Subject();
1232
+ }
1233
+ get fieldAsyncValidation$() {
1234
+ return this.fieldAsyncValidation.asObservable();
1250
1235
  }
1251
1236
  setup(form, fields) {
1252
1237
  this.reset();
@@ -1271,24 +1256,23 @@ class SyncService extends EmitDataService {
1271
1256
  }
1272
1257
  if (prevFieldState && value === prevFieldState.value) {
1273
1258
  return Promise.resolve(prevFieldState.result).then((response) => {
1274
- return response?.rewritableError ?? null;
1259
+ return response?.error ?? null;
1275
1260
  });
1276
1261
  }
1277
1262
  const requestPromise = this.request(field);
1278
1263
  this.setPrevFieldSyncState(field, value, requestPromise);
1279
1264
  return requestPromise.then((response) => {
1280
- return response.rewritableError ?? null;
1265
+ this.fieldAsyncValidation.next({
1266
+ value,
1267
+ field,
1268
+ response,
1269
+ });
1270
+ return response.error ?? null;
1281
1271
  });
1282
1272
  }
1283
1273
  getSyncValidationErrors(field) {
1284
1274
  const control = this.form.get(field.name);
1285
- if (!control) {
1286
- return null;
1287
- }
1288
- const rewritableError = control.errors?.rewritableError;
1289
- return rewritableError
1290
- ? { message: rewritableError.message, code: rewritableError.code }
1291
- : null;
1275
+ return control?.errors ?? null;
1292
1276
  }
1293
1277
  async request(field) {
1294
1278
  const requestParams = this.requestFactory({
@@ -1348,44 +1332,28 @@ class TextControlConfig extends ControlConfig {
1348
1332
  }
1349
1333
  }
1350
1334
 
1351
- function convert(validator, message, errorCode) {
1335
+ function convert(validator, message) {
1352
1336
  return (control) => {
1353
1337
  const errors = validator(control);
1354
1338
  if (!errors) {
1355
1339
  return errors;
1356
1340
  }
1357
1341
  const firstErrorKey = Object.keys(errors)[0];
1358
- let error = errors[firstErrorKey];
1359
- error = typeof error === 'object' && error !== null ? error : {};
1360
- const rewritableError = { ...error };
1361
- rewritableError.message = message;
1362
- rewritableError.code = errorCode;
1363
- if (error[firstErrorKey] != null) {
1364
- rewritableError.value = error[firstErrorKey];
1365
- }
1366
- if (rewritableError.requiredLength) {
1367
- rewritableError.number = rewritableError.requiredLength;
1368
- }
1369
- errors.rewritableError = rewritableError;
1342
+ const firstError = errors[firstErrorKey];
1343
+ const error = typeof firstError === 'object' && firstError !== null ? firstError : {};
1344
+ error.message = message;
1345
+ errors[firstErrorKey] = error;
1370
1346
  return errors;
1371
1347
  };
1372
1348
  }
1373
1349
 
1374
- var ErrorsCodes;
1375
- (function (ErrorsCodes) {
1376
- ErrorsCodes["minLength"] = "min-length";
1377
- ErrorsCodes["maxLength"] = "max-length";
1378
- ErrorsCodes["invalidValue"] = "invalid-value";
1379
- ErrorsCodes["required"] = "required";
1380
- })(ErrorsCodes || (ErrorsCodes = {}));
1381
-
1382
1350
  const emailRegexp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; // eslint-disable-line
1383
- function emailValidator() {
1384
- return convert(Validators.pattern(emailRegexp), 'Enter a valid email', ErrorsCodes.invalidValue);
1351
+ function convertedEmailValidator() {
1352
+ return convert(Validators.pattern(emailRegexp), 'Enter a valid email');
1385
1353
  }
1386
1354
 
1387
- function requiredValidator() {
1388
- return convert(Validators.required, 'Required', ErrorsCodes.required);
1355
+ function convertedRequiredValidator() {
1356
+ return convert(Validators.required, 'Required');
1389
1357
  }
1390
1358
 
1391
1359
  class Converter {
@@ -1400,12 +1368,12 @@ class Converter {
1400
1368
  return config;
1401
1369
  }
1402
1370
  convertToFormControl(field) {
1403
- return new UntypedFormControl(this.getValue(field), this.getValidators(field));
1371
+ return new UntypedFormControl(this.getValue(field), this.getValidators(field), this.getAsyncValidators(field));
1404
1372
  }
1405
1373
  getValidators(field) {
1406
1374
  const validators = [];
1407
1375
  if (field.isMandatory === "1" /* XpsBoolean.true */) {
1408
- validators.push(requiredValidator());
1376
+ validators.push(convertedRequiredValidator());
1409
1377
  }
1410
1378
  if (field.regex) {
1411
1379
  const match = /^\/(.*)\/([gim]*)$/.exec(field.regex);
@@ -1414,11 +1382,14 @@ class Converter {
1414
1382
  const errorMessage = field.validation_error_msg
1415
1383
  ? field.validation_error_msg
1416
1384
  : 'Enter valid data';
1417
- validators.push(convert(Validators.pattern(pattern), errorMessage, ErrorsCodes.invalidValue));
1385
+ validators.push(convert(Validators.pattern(pattern), errorMessage));
1418
1386
  }
1419
1387
  }
1420
1388
  return validators;
1421
1389
  }
1390
+ getAsyncValidators(field) {
1391
+ return async () => this.syncService.validate(field);
1392
+ }
1422
1393
  createDefaultControlConfig(controlConfigClass, field) {
1423
1394
  const config = new controlConfigClass();
1424
1395
  this.copyCommonOptions(config, field);
@@ -1462,7 +1433,7 @@ class EmailConverter extends Converter {
1462
1433
  super(syncService);
1463
1434
  }
1464
1435
  getValidators(field) {
1465
- return super.getValidators(field).concat([emailValidator()]);
1436
+ return super.getValidators(field).concat([convertedEmailValidator()]);
1466
1437
  }
1467
1438
  createControlConfig(field) {
1468
1439
  const config = this.createDefaultControlConfig(TextControlConfig, field);
@@ -1503,11 +1474,11 @@ class ZipConverter extends Converter {
1503
1474
  const validators = super
1504
1475
  .getValidators(field)
1505
1476
  .concat([
1506
- convert(Validators.minLength(minLength), `Enter at least ${minLength} characters`, ErrorsCodes.minLength),
1507
- convert(Validators.maxLength(maxLength), `Enter no more than ${maxLength} characters`, ErrorsCodes.maxLength),
1477
+ convert(Validators.minLength(minLength), `Enter at least ${minLength} characters`),
1478
+ convert(Validators.maxLength(maxLength), `Enter no more than ${maxLength} characters`),
1508
1479
  ]);
1509
1480
  if (this.isUsCountry) {
1510
- validators.push(convert(restrictedValueValidator('00000'), 'Enter a valid ZIP code', ErrorsCodes.invalidValue));
1481
+ validators.push(convert(restrictedValueValidator('00000'), 'Enter a valid ZIP code'));
1511
1482
  }
1512
1483
  return validators;
1513
1484
  }
@@ -1543,10 +1514,430 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImpor
1543
1514
  type: Injectable
1544
1515
  }], ctorParameters: function () { return [{ type: SyncService }, { type: CountryService }]; } });
1545
1516
 
1517
+ function isEmptyInputValue(value) {
1518
+ return value == null || value.length === 0;
1519
+ }
1520
+
1521
+ function isString(value) {
1522
+ return typeof value === 'string';
1523
+ }
1524
+
1525
+ /**
1526
+ * Checks number match Luhn algorithm.
1527
+ * Based on http://en.wikipedia.org/wiki/Luhn.
1528
+ */
1529
+ const luhnFormulaValidator = ({ value }) => {
1530
+ if (isEmptyInputValue(value) || !isString(value)) {
1531
+ return null;
1532
+ }
1533
+ const error = {
1534
+ rewritableError: {
1535
+ message: `Enter a valid card number`,
1536
+ },
1537
+ };
1538
+ if (/[^0-9 -]+/.test(value)) {
1539
+ // accept only spaces, digits and dashes
1540
+ return error;
1541
+ }
1542
+ let resultSum = 0;
1543
+ let digit = 0;
1544
+ let isEven = false;
1545
+ const modBase = 10;
1546
+ const digitRadix = 10;
1547
+ const maxNumber = 9;
1548
+ const digits = value.replace(/\D/g, '');
1549
+ // Checks if number match Luhn algorithm
1550
+ // based on http://en.wikipedia.org/wiki/Luhn
1551
+ for (let index = digits.length - 1; index >= 0; index--) {
1552
+ const char = digits.charAt(index);
1553
+ digit = parseInt(char, digitRadix);
1554
+ if (isEven && (digit *= 2) > maxNumber) {
1555
+ digit -= maxNumber;
1556
+ }
1557
+ resultSum += digit;
1558
+ isEven = !isEven;
1559
+ }
1560
+ return resultSum % modBase === 0 ? null : error;
1561
+ };
1562
+
1563
+ class CardNumberConfig extends ControlConfig {
1564
+ constructor() {
1565
+ super(...arguments);
1566
+ this.controlType = 'card-number';
1567
+ this.availableCardTypes = [];
1568
+ this.customError = '';
1569
+ }
1570
+ }
1571
+
1572
+ const fourBlockMask = '9999 9999 9999 9999';
1573
+
1574
+ var CreditCardTypes;
1575
+ (function (CreditCardTypes) {
1576
+ CreditCardTypes["DEFAULT"] = "0";
1577
+ CreditCardTypes["VISA"] = "1";
1578
+ CreditCardTypes["MASTERCARD"] = "2";
1579
+ CreditCardTypes["MAESTRO"] = "3";
1580
+ CreditCardTypes["AMERICAN_EXPRESS"] = "4";
1581
+ CreditCardTypes["DINERS_CLUBS"] = "5";
1582
+ CreditCardTypes["DISCOVER"] = "6";
1583
+ CreditCardTypes["JCB"] = "9";
1584
+ CreditCardTypes["DANKORT"] = "11";
1585
+ CreditCardTypes["HIPERCARD"] = "12";
1586
+ CreditCardTypes["ELO"] = "13";
1587
+ CreditCardTypes["AURA"] = "14";
1588
+ CreditCardTypes["NARANJA"] = "15";
1589
+ CreditCardTypes["MIR"] = "16";
1590
+ CreditCardTypes["CHINA_UNION_PAY"] = "17";
1591
+ CreditCardTypes["POSTEPAY"] = "18";
1592
+ })(CreditCardTypes || (CreditCardTypes = {}));
1593
+
1594
+ const visa = {
1595
+ id: CreditCardTypes.VISA,
1596
+ minLength: 13,
1597
+ maxLength: 16,
1598
+ iconName: 'visa',
1599
+ mask: fourBlockMask,
1600
+ checkNumber(number) {
1601
+ return number.startsWith('4');
1602
+ },
1603
+ };
1604
+
1605
+ const mastercard = {
1606
+ id: CreditCardTypes.MASTERCARD,
1607
+ minLength: 16,
1608
+ maxLength: 16,
1609
+ iconName: 'mastercard',
1610
+ mask: fourBlockMask,
1611
+ checkNumber(number) {
1612
+ const subLength = 6;
1613
+ const cardNumberSub = number.substring(0, subLength);
1614
+ return (new RegExp(/^5[1-5]/).test(number) ||
1615
+ (cardNumberSub >= '222100' && cardNumberSub <= '272099'));
1616
+ },
1617
+ };
1618
+
1619
+ const defaultMask = '9999 9999 9999 9999 999';
1620
+
1621
+ const maestro = {
1622
+ id: CreditCardTypes.MAESTRO,
1623
+ minLength: 12,
1624
+ maxLength: 19,
1625
+ iconName: 'maestro',
1626
+ mask: defaultMask,
1627
+ checkNumber(number) {
1628
+ return new RegExp(/^(5018)|^(5020)|^(5038)|^(5893)|^(6304)|^(6759)|^(6761)|^(6762)|^(6763)|^(0604)|^(6706)|^(6771)|^(6709)/).test(number);
1629
+ },
1630
+ maxCvvLength: 3,
1631
+ };
1632
+
1633
+ const americanExpress = {
1634
+ id: CreditCardTypes.AMERICAN_EXPRESS,
1635
+ minLength: 15,
1636
+ maxLength: 15,
1637
+ iconName: 'american-express',
1638
+ mask: '9999 999999 99999',
1639
+ checkNumber(number) {
1640
+ return new RegExp(/^(34)|^(37)/).test(number);
1641
+ },
1642
+ maxCvvLength: 4,
1643
+ };
1644
+
1645
+ const dinersClubs = {
1646
+ id: CreditCardTypes.DINERS_CLUBS,
1647
+ minLength: 14,
1648
+ maxLength: 14,
1649
+ iconName: 'dinersclub',
1650
+ mask: '9999 9999 9999 99',
1651
+ checkNumber(number) {
1652
+ const regex = /^(36[0-9]|3(?:0[0-59]|[68][0-9])[0-9])/;
1653
+ return regex.test(number);
1654
+ },
1655
+ };
1656
+
1657
+ const discover = {
1658
+ id: CreditCardTypes.DISCOVER,
1659
+ minLength: 16,
1660
+ maxLength: 19,
1661
+ iconName: 'discover',
1662
+ mask: defaultMask,
1663
+ checkNumber(number) {
1664
+ return new RegExp(/^(6011)|^(622(1(2[6-9]|[3-9][0-9])|[2-8][0-9]{2}|9([01][0-9]|2[0-5])))|^(64[4-9])|^65/).test(number);
1665
+ },
1666
+ };
1667
+
1668
+ const jcb = {
1669
+ id: CreditCardTypes.JCB,
1670
+ minLength: 15,
1671
+ maxLength: 16,
1672
+ iconName: 'jcb',
1673
+ mask: fourBlockMask,
1674
+ checkNumber(number) {
1675
+ return new RegExp(/^35(2[89]|[3-8][0-9])/).test(number);
1676
+ },
1677
+ };
1678
+
1679
+ const dankort = {
1680
+ id: CreditCardTypes.DANKORT,
1681
+ minLength: 16,
1682
+ maxLength: 16,
1683
+ iconName: 'dankort',
1684
+ mask: fourBlockMask,
1685
+ checkNumber(number) {
1686
+ const subLength = 4;
1687
+ const cardNumberSub = number.substring(0, subLength);
1688
+ return cardNumberSub === '5019';
1689
+ },
1690
+ };
1691
+
1692
+ const hipercard = {
1693
+ id: CreditCardTypes.HIPERCARD,
1694
+ minLength: 13,
1695
+ maxLength: 19,
1696
+ iconName: 'hipercard',
1697
+ mask: defaultMask,
1698
+ checkNumber(number) {
1699
+ return new RegExp(/^((606282|637095|637568)[0-9]|38[0-9]{14,17})/).test(number);
1700
+ },
1701
+ };
1702
+
1703
+ const elo = {
1704
+ id: CreditCardTypes.ELO,
1705
+ minLength: 16,
1706
+ maxLength: 19,
1707
+ iconName: 'elo',
1708
+ mask: defaultMask,
1709
+ checkNumber(number) {
1710
+ return new RegExp(/^(40117[8-9]|431274|438935|451416|457393|45763[1-2]|506(699|7[0-6][0-9]|77[0-8])|509\d{3}|504175|627780|636297|636368|65003[1-3]|6500(3[5-9]|4[0-9]|5[0-1])|6504(0[5-9]|[1-3][0-9])|650(4[8-9][0-9]|5[0-2][0-9]|53[0-8])|6505(4[1-9]|[5-8][0-9]|9[0-8])|6507(0[0-9]|1[0-8])|65072[0-7]|6509(0[1-9]|1[0-9]|20)|6516(5[2-9]|[6-7][0-9])|6550([0-1][0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/).test(number);
1711
+ },
1712
+ };
1713
+
1714
+ const aura = {
1715
+ id: CreditCardTypes.AURA,
1716
+ minLength: 16,
1717
+ maxLength: 19,
1718
+ iconName: 'aura',
1719
+ mask: defaultMask,
1720
+ checkNumber(number) {
1721
+ const subLength = 8;
1722
+ const cardNumberSub = number.substring(0, subLength);
1723
+ return ['50786000', '50786018', '50786019'].includes(cardNumberSub);
1724
+ },
1725
+ };
1726
+
1727
+ const naranja = {
1728
+ id: CreditCardTypes.NARANJA,
1729
+ minLength: 12,
1730
+ maxLength: 19,
1731
+ iconName: 'naranja',
1732
+ mask: defaultMask,
1733
+ checkNumber(number) {
1734
+ const subLength = 6;
1735
+ const cardNumberSub = number.substring(0, subLength);
1736
+ return cardNumberSub === '589562';
1737
+ },
1738
+ };
1739
+
1740
+ const mir = {
1741
+ id: CreditCardTypes.MIR,
1742
+ minLength: 16,
1743
+ maxLength: 16,
1744
+ iconName: 'mir',
1745
+ mask: defaultMask,
1746
+ checkNumber(number) {
1747
+ const subLength = 4;
1748
+ const cardNumberSub = number.substring(0, subLength);
1749
+ return cardNumberSub >= '2200' && cardNumberSub <= '2204';
1750
+ },
1751
+ };
1752
+
1753
+ const chinaUnionPay = {
1754
+ id: CreditCardTypes.CHINA_UNION_PAY,
1755
+ minLength: 16,
1756
+ maxLength: 19,
1757
+ iconName: 'unionpay',
1758
+ mask: '999 9999 9999 99999999',
1759
+ checkNumber(number) {
1760
+ return number.startsWith('62');
1761
+ },
1762
+ };
1763
+
1764
+ const defaultCard = {
1765
+ id: CreditCardTypes.DEFAULT,
1766
+ minLength: 12,
1767
+ maxLength: 19,
1768
+ iconName: null,
1769
+ mask: defaultMask,
1770
+ checkNumber() {
1771
+ return false;
1772
+ },
1773
+ };
1774
+
1775
+ const postePay = {
1776
+ id: CreditCardTypes.POSTEPAY,
1777
+ minLength: 12,
1778
+ maxLength: 19,
1779
+ iconName: 'poste_pay',
1780
+ mask: '9999 9999 9999 9999 999',
1781
+ checkNumber(number) {
1782
+ const regex = /^(5018)|^(5020)|^(5038)|^(5893)|^(6304)|^(6759)|^(6761)|^(6762)|^(6763)|^(0604)|^(6706)|^(6771)|^(6709)/;
1783
+ return regex.test(number);
1784
+ },
1785
+ };
1786
+
1787
+ /**
1788
+ * order does matter
1789
+ * settings with more specific pattern should be placed above
1790
+ * Example:
1791
+ * - 12*
1792
+ * - 12
1793
+ * - 1
1794
+ * "12*" pattern should be checked first, otherwise pattern "1" will be taken
1795
+ * before "12*" checked
1796
+ */
1797
+ const orderedCardSettings = [
1798
+ aura,
1799
+ naranja,
1800
+ maestro,
1801
+ postePay,
1802
+ elo,
1803
+ discover,
1804
+ dankort,
1805
+ hipercard,
1806
+ mir,
1807
+ jcb,
1808
+ dinersClubs,
1809
+ americanExpress,
1810
+ mastercard,
1811
+ chinaUnionPay,
1812
+ visa,
1813
+ defaultCard,
1814
+ ];
1815
+
1816
+ const creditCardsMap = {
1817
+ [CreditCardTypes.DEFAULT]: defaultCard,
1818
+ [CreditCardTypes.VISA]: visa,
1819
+ [CreditCardTypes.MASTERCARD]: mastercard,
1820
+ [CreditCardTypes.MAESTRO]: maestro,
1821
+ [CreditCardTypes.AMERICAN_EXPRESS]: americanExpress,
1822
+ [CreditCardTypes.DINERS_CLUBS]: dinersClubs,
1823
+ [CreditCardTypes.DISCOVER]: discover,
1824
+ [CreditCardTypes.JCB]: jcb,
1825
+ [CreditCardTypes.DANKORT]: dankort,
1826
+ [CreditCardTypes.HIPERCARD]: hipercard,
1827
+ [CreditCardTypes.ELO]: elo,
1828
+ [CreditCardTypes.AURA]: aura,
1829
+ [CreditCardTypes.NARANJA]: naranja,
1830
+ [CreditCardTypes.MIR]: mir,
1831
+ [CreditCardTypes.CHINA_UNION_PAY]: chinaUnionPay,
1832
+ [CreditCardTypes.POSTEPAY]: postePay,
1833
+ };
1834
+
1835
+ class CreditCardService {
1836
+ getBinNumber(cardNumber) {
1837
+ const binNumberLength = 6;
1838
+ return cardNumber.replace(/\s+/g, '').substring(0, binNumberLength);
1839
+ }
1840
+ getAccountSuffix(cardNumber) {
1841
+ const accountSuffixLength = 4;
1842
+ return cardNumber
1843
+ .replace(/\s+/g, '')
1844
+ .substring(cardNumber.length - accountSuffixLength);
1845
+ }
1846
+ getTypeByNumber(cardNumber) {
1847
+ cardNumber = cardNumber.replace(/\s+/g, '');
1848
+ const cardSettings = orderedCardSettings.find((settings) => {
1849
+ const isNumberMatched = settings.checkNumber(cardNumber);
1850
+ return isNumberMatched ? settings.id : false;
1851
+ });
1852
+ return cardSettings ? cardSettings.id : defaultCard.id;
1853
+ }
1854
+ getCreditCardSettings(cardType) {
1855
+ const creditCard = creditCardsMap[cardType];
1856
+ if (!creditCard) {
1857
+ return defaultCard;
1858
+ }
1859
+ return creditCard;
1860
+ }
1861
+ }
1862
+ CreditCardService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1863
+ CreditCardService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardService, providedIn: 'root' });
1864
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardService, decorators: [{
1865
+ type: Injectable,
1866
+ args: [{
1867
+ providedIn: 'root',
1868
+ }]
1869
+ }] });
1870
+
1871
+ class CreditCardMinLengthValidator {
1872
+ constructor(creditService) {
1873
+ this.creditService = creditService;
1874
+ this.validate = (field) => {
1875
+ if (isEmptyInputValue(field.value) || !isString(field.value)) {
1876
+ return null;
1877
+ }
1878
+ const length = field.value.length;
1879
+ const cardType = this.creditService.getTypeByNumber(field.value);
1880
+ const { minLength } = this.creditService.getCreditCardSettings(cardType);
1881
+ return length < minLength
1882
+ ? {
1883
+ rewritableError: {
1884
+ message: `Enter at least ${minLength} characters`,
1885
+ number: minLength,
1886
+ },
1887
+ }
1888
+ : null;
1889
+ };
1890
+ }
1891
+ }
1892
+ CreditCardMinLengthValidator.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardMinLengthValidator, deps: [{ token: CreditCardService }], target: i0.ɵɵFactoryTarget.Injectable });
1893
+ CreditCardMinLengthValidator.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardMinLengthValidator });
1894
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardMinLengthValidator, decorators: [{
1895
+ type: Injectable
1896
+ }], ctorParameters: function () { return [{ type: CreditCardService }]; } });
1897
+
1898
+ class CardNumberConverter extends Converter {
1899
+ constructor(syncService, maxLengthValidator, minLengthValidator) {
1900
+ super(syncService);
1901
+ this.maxLengthValidator = maxLengthValidator;
1902
+ this.minLengthValidator = minLengthValidator;
1903
+ }
1904
+ getValidators(field) {
1905
+ return super
1906
+ .getValidators(field)
1907
+ .concat([
1908
+ luhnFormulaValidator,
1909
+ this.minLengthValidator.validate,
1910
+ this.maxLengthValidator.validate,
1911
+ ]);
1912
+ }
1913
+ createControlConfig(field, formState) {
1914
+ const config = this.createDefaultControlConfig(CardNumberConfig, field);
1915
+ config.placeholder = config.title;
1916
+ config.availableCardTypes =
1917
+ formState?.availableCardTypes ?? [];
1918
+ config.activeCardType = formState?.activeCardType;
1919
+ config.customError = formState?.customError;
1920
+ config.disabled = formState?.disabled ?? false;
1921
+ return config;
1922
+ }
1923
+ getAutocomplete() {
1924
+ return 'cc-number';
1925
+ }
1926
+ getDataType() {
1927
+ return 'text';
1928
+ }
1929
+ }
1930
+ CardNumberConverter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CardNumberConverter, deps: [{ token: SyncService }, { token: CreditCardMinLengthValidator }, { token: CreditCardMinLengthValidator }], target: i0.ɵɵFactoryTarget.Injectable });
1931
+ CardNumberConverter.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CardNumberConverter });
1932
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CardNumberConverter, decorators: [{
1933
+ type: Injectable
1934
+ }], ctorParameters: function () { return [{ type: SyncService }, { type: CreditCardMinLengthValidator }, { type: CreditCardMinLengthValidator }]; } });
1935
+
1546
1936
  const convertersMapToken = new InjectionToken('ConvertersTokensMap');
1547
1937
  const convertersMap = {
1548
1938
  zip: ZipConverter,
1549
1939
  email: EmailConverter,
1940
+ card_number: CardNumberConverter,
1550
1941
  };
1551
1942
 
1552
1943
  class ControlConfigService {
@@ -3007,22 +3398,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImpor
3007
3398
  args: [financeDetailsResponseFactoryToken]
3008
3399
  }] }]; } });
3009
3400
 
3401
+ class CreditCardStateService extends EmitDataService {
3402
+ }
3403
+ CreditCardStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardStateService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
3404
+ CreditCardStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardStateService, providedIn: 'root' });
3405
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CreditCardStateService, decorators: [{
3406
+ type: Injectable,
3407
+ args: [{
3408
+ providedIn: 'root',
3409
+ }]
3410
+ }] });
3411
+
3010
3412
  class PaymentService {
3011
- constructor(initializeService, submitService, syncService, formService, statusService, financeDetailsService, nextActionService, controlConfigService) {
3413
+ get formFieldsStatus$() {
3414
+ return this.formFieldsStatusSubject.asObservable().pipe(filter$1(Boolean));
3415
+ }
3416
+ constructor(initializeService, submitService, syncService, formService, statusService, financeDetailsService, creditCardStateService, nextActionService, controlConfigService) {
3012
3417
  this.initializeService = initializeService;
3013
3418
  this.submitService = submitService;
3014
3419
  this.syncService = syncService;
3015
3420
  this.formService = formService;
3016
3421
  this.statusService = statusService;
3017
3422
  this.financeDetailsService = financeDetailsService;
3423
+ this.creditCardStateService = creditCardStateService;
3018
3424
  this.nextActionService = nextActionService;
3019
3425
  this.controlConfigService = controlConfigService;
3020
3426
  this.form = null;
3021
3427
  this.data = null;
3022
3428
  this.financeDetails = null;
3429
+ this.focusFieldName = null;
3023
3430
  this.fields = [];
3024
3431
  this.destroy$ = new Subject();
3025
3432
  this.formDestroy$ = new Subject();
3433
+ this.formFieldsStatusSubject = new BehaviorSubject(null);
3026
3434
  }
3027
3435
  async initialize(config) {
3028
3436
  this.destroy$ = new Subject();
@@ -3032,9 +3440,10 @@ class PaymentService {
3032
3440
  this.data = await this.initializeService.request(config);
3033
3441
  this.fields = this.getFields();
3034
3442
  this.form = this.formService.createForm(this.fields);
3035
- this.listenSyncValidationErrors(this.form);
3036
- this.emitFinanceDetails(this.data.paymentForm?.summary);
3037
3443
  this.setupSyncService(this.form, this.fields);
3444
+ this.listenFormStatusChanges(this.form);
3445
+ this.emitFinanceDetails(this.data.paymentForm?.summary);
3446
+ this.emitFormFieldsStatus(this.form);
3038
3447
  return this.fields.filter((field) => field?.isVisible === "1" /* XpsBoolean.true */);
3039
3448
  }
3040
3449
  async submit() {
@@ -3043,13 +3452,7 @@ class PaymentService {
3043
3452
  }
3044
3453
  if (!this.form.valid) {
3045
3454
  this.form.markAllAsTouched();
3046
- Object.keys(this.form.controls).forEach((controlKey) => {
3047
- const control = this.form?.get(controlKey);
3048
- if (control) {
3049
- const controlObject = this.getControlState(controlKey, control);
3050
- this.nextActionService.emitFlowUpdates(new ShowFieldStateAction({ ...controlObject, isFocused: true }));
3051
- }
3052
- });
3455
+ this.emitFormFieldsStatus(this.form);
3053
3456
  return;
3054
3457
  }
3055
3458
  const submitResponse = await this.submitService.request(this.fields, this.form);
@@ -3098,22 +3501,22 @@ class PaymentService {
3098
3501
  }
3099
3502
  changeFieldState(name, state) {
3100
3503
  const formControl = this.form?.get(name);
3101
- if (!formControl) {
3504
+ if (!this.form || !formControl) {
3102
3505
  return;
3103
3506
  }
3104
- const controlObject = this.getControlState(name, formControl);
3105
3507
  switch (state) {
3106
3508
  case InputEventName.blur: {
3107
3509
  formControl.markAsTouched();
3108
- this.nextActionService.emitFlowUpdates(new ShowFieldStateAction({ ...controlObject, isFocused: true }));
3109
- return;
3510
+ this.focusFieldName = null;
3511
+ break;
3110
3512
  }
3111
3513
  case InputEventName.focus: {
3112
3514
  formControl.markAsUntouched();
3113
- this.nextActionService.emitFlowUpdates(new ShowFieldStateAction({ ...controlObject, isFocused: false }));
3114
- return;
3515
+ this.focusFieldName = name;
3516
+ break;
3115
3517
  }
3116
3518
  }
3519
+ this.emitFormFieldsStatus(this.form);
3117
3520
  }
3118
3521
  destroy() {
3119
3522
  this.data = null;
@@ -3126,48 +3529,57 @@ class PaymentService {
3126
3529
  emitFinanceDetails(summary) {
3127
3530
  this.financeDetailsService.emit(summary);
3128
3531
  }
3532
+ emitCreditCardState(idCardType) {
3533
+ this.creditCardStateService.emit({ idCardType });
3534
+ }
3535
+ emitFormFieldsStatus(form) {
3536
+ const formFieldsStatus = {};
3537
+ Object.keys(form.controls).forEach((name) => {
3538
+ const control = form.controls[name];
3539
+ formFieldsStatus[name] = {
3540
+ name: name,
3541
+ validationStatus: control.status,
3542
+ errors: control.errors,
3543
+ isFocused: this.focusFieldName === name,
3544
+ };
3545
+ });
3546
+ this.formFieldsStatusSubject.next(formFieldsStatus);
3547
+ }
3129
3548
  setupSyncService(form, fields) {
3130
3549
  this.syncService.setup(form, fields);
3131
3550
  this.syncService.data$
3132
3551
  .pipe(takeUntil(this.destroy$))
3133
- .subscribe((response) => this.emitFinanceDetails(response.summary));
3552
+ .subscribe((response) => {
3553
+ this.emitFinanceDetails(response.summary);
3554
+ });
3555
+ this.syncService.fieldAsyncValidation$
3556
+ .pipe(takeUntil(this.destroy$))
3557
+ .subscribe((fieldAsyncValidation) => {
3558
+ switch (fieldAsyncValidation.field.name) {
3559
+ case FieldNames.cardNumber:
3560
+ this.emitCreditCardState(fieldAsyncValidation.response.parameters.idCardType);
3561
+ }
3562
+ });
3134
3563
  }
3135
3564
  listenFinanceDetails() {
3136
3565
  this.financeDetailsService.data$
3137
3566
  .pipe(takeUntil(this.destroy$))
3138
3567
  .subscribe((financeDetails) => (this.financeDetails = financeDetails));
3139
3568
  }
3140
- listenSyncValidationErrors(form) {
3141
- Object.keys(form.controls).forEach((key) => {
3142
- const control = form.get(key);
3143
- if (control) {
3144
- control.statusChanges
3145
- .pipe(distinctUntilChanged(), takeUntil(this.formDestroy$))
3146
- .subscribe((status) => {
3147
- const controlObject = this.getControlState(key, control, status);
3148
- this.nextActionService.emitFlowUpdates(new ShowFieldStateAction(controlObject));
3149
- });
3150
- }
3151
- });
3152
- }
3153
- getControlState(controlName, controlObject, status) {
3154
- const controlError = controlObject.errors?.['rewritableError'] ??
3155
- null;
3156
- return {
3157
- fieldName: controlName,
3158
- fieldState: status ?? controlObject.status,
3159
- error: controlError,
3160
- };
3569
+ listenFormStatusChanges(form) {
3570
+ form.statusChanges
3571
+ .pipe(takeUntil(this.formDestroy$))
3572
+ .subscribe(() => this.emitFormFieldsStatus(form));
3161
3573
  }
3162
3574
  }
3163
- PaymentService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: PaymentService, deps: [{ token: InitializeService }, { token: SubmitService }, { token: SyncService }, { token: FormService }, { token: StatusService }, { token: FinanceDetailsService }, { token: NextActionService }, { token: ControlConfigService }], target: i0.ɵɵFactoryTarget.Injectable });
3575
+ PaymentService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: PaymentService, deps: [{ token: InitializeService }, { token: SubmitService }, { token: SyncService }, { token: FormService }, { token: StatusService }, { token: FinanceDetailsService }, { token: CreditCardStateService }, { token: NextActionService }, { token: ControlConfigService }], target: i0.ɵɵFactoryTarget.Injectable });
3164
3576
  PaymentService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: PaymentService, providedIn: 'root' });
3165
3577
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: PaymentService, decorators: [{
3166
3578
  type: Injectable,
3167
3579
  args: [{
3168
3580
  providedIn: 'root',
3169
3581
  }]
3170
- }], ctorParameters: function () { return [{ type: InitializeService }, { type: SubmitService }, { type: SyncService }, { type: FormService }, { type: StatusService }, { type: FinanceDetailsService }, { type: NextActionService }, { type: ControlConfigService }]; } });
3582
+ }], ctorParameters: function () { return [{ type: InitializeService }, { type: SubmitService }, { type: SyncService }, { type: FormService }, { type: StatusService }, { type: FinanceDetailsService }, { type: CreditCardStateService }, { type: NextActionService }, { type: ControlConfigService }]; } });
3171
3583
 
3172
3584
  class RefundPolicyService {
3173
3585
  constructor(settingsService) {
@@ -3272,7 +3684,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImpor
3272
3684
  }], ctorParameters: function () { return [{ type: SettingsService }, { type: RefundPolicyService }, { type: SecureConnectionService }, { type: DisclaimerService }]; } });
3273
3685
 
3274
3686
  class CoreLibraryService {
3275
- constructor(settingsService, countryService, paymentMethodsService, savedMethodsService, userBalanceService, paymentConfigService, paymentService, deviceFingerPrintService, financeDetailsService, legalService, statusService, nextActionService) {
3687
+ constructor(settingsService, countryService, paymentMethodsService, savedMethodsService, userBalanceService, paymentConfigService, paymentService, deviceFingerPrintService, financeDetailsService, legalService, statusService, nextActionService, creditCardService, creditCardStateService) {
3276
3688
  this.settingsService = settingsService;
3277
3689
  this.countryService = countryService;
3278
3690
  this.paymentMethodsService = paymentMethodsService;
@@ -3285,6 +3697,8 @@ class CoreLibraryService {
3285
3697
  this.legalService = legalService;
3286
3698
  this.statusService = statusService;
3287
3699
  this.nextActionService = nextActionService;
3700
+ this.creditCardService = creditCardService;
3701
+ this.creditCardStateService = creditCardStateService;
3288
3702
  this.paymentMethods = {
3289
3703
  getList: async () => this.paymentMethodsService.getList(),
3290
3704
  getQuickMethods: async () => this.paymentMethodsService.getQuickMethods(),
@@ -3315,14 +3729,23 @@ class CoreLibraryService {
3315
3729
  flowUpdates$: this.nextActionService.flowUpdates$,
3316
3730
  financeDetailsUpdates$: this.financeDetailsService.data$,
3317
3731
  form: {
3732
+ fieldsStatus$: this.paymentService.formFieldsStatus$,
3318
3733
  getControlConfig: (field) => this.paymentService.getFieldConfig(field),
3319
3734
  changeFieldValue: (name, value) => this.paymentService.changeFieldValue(name, value),
3320
- changeFieldState: (name, state) => {
3321
- this.paymentService.changeFieldState(name, state);
3322
- },
3735
+ changeFieldState: (name, state) => this.paymentService.changeFieldState(name, state),
3323
3736
  },
3324
3737
  };
3325
3738
  }
3739
+ getCreditCardService() {
3740
+ return {
3741
+ getTypeByNumber: (cardNumber) => this.creditCardService.getTypeByNumber(cardNumber),
3742
+ getCreditCardSettings: (cardType) => this.creditCardService.getCreditCardSettings(cardType),
3743
+ cardTypeUpdates$: this.creditCardStateService.data$,
3744
+ };
3745
+ }
3746
+ get cardTypeUpdates$() {
3747
+ return this.creditCardStateService.data$;
3748
+ }
3326
3749
  getLegalComponentConfig() {
3327
3750
  return this.legalService.getLegalComponentConfig();
3328
3751
  }
@@ -3331,14 +3754,14 @@ class CoreLibraryService {
3331
3754
  return masksFunctionsMap[sanitizedName];
3332
3755
  }
3333
3756
  }
3334
- CoreLibraryService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CoreLibraryService, deps: [{ token: SettingsService }, { token: CountryService }, { token: PaymentMethodsService }, { token: SavedMethodsService }, { token: UserBalanceService }, { token: PaymentConfigService }, { token: PaymentService }, { token: DeviceFingerPrintService }, { token: FinanceDetailsService }, { token: LegalService }, { token: StatusService }, { token: NextActionService }], target: i0.ɵɵFactoryTarget.Injectable });
3757
+ CoreLibraryService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CoreLibraryService, deps: [{ token: SettingsService }, { token: CountryService }, { token: PaymentMethodsService }, { token: SavedMethodsService }, { token: UserBalanceService }, { token: PaymentConfigService }, { token: PaymentService }, { token: DeviceFingerPrintService }, { token: FinanceDetailsService }, { token: LegalService }, { token: StatusService }, { token: NextActionService }, { token: CreditCardService }, { token: CreditCardStateService }], target: i0.ɵɵFactoryTarget.Injectable });
3335
3758
  CoreLibraryService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CoreLibraryService, providedIn: 'root' });
3336
3759
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: CoreLibraryService, decorators: [{
3337
3760
  type: Injectable,
3338
3761
  args: [{
3339
3762
  providedIn: 'root',
3340
3763
  }]
3341
- }], ctorParameters: function () { return [{ type: SettingsService }, { type: CountryService }, { type: PaymentMethodsService }, { type: SavedMethodsService }, { type: UserBalanceService }, { type: PaymentConfigService }, { type: PaymentService }, { type: DeviceFingerPrintService }, { type: FinanceDetailsService }, { type: LegalService }, { type: StatusService }, { type: NextActionService }]; } });
3764
+ }], ctorParameters: function () { return [{ type: SettingsService }, { type: CountryService }, { type: PaymentMethodsService }, { type: SavedMethodsService }, { type: UserBalanceService }, { type: PaymentConfigService }, { type: PaymentService }, { type: DeviceFingerPrintService }, { type: FinanceDetailsService }, { type: LegalService }, { type: StatusService }, { type: NextActionService }, { type: CreditCardService }, { type: CreditCardStateService }]; } });
3342
3765
 
3343
3766
  class HttpError extends AppError {
3344
3767
  constructor(error, req) {
@@ -3395,26 +3818,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImpor
3395
3818
  type: Injectable
3396
3819
  }], ctorParameters: function () { return [{ type: i1$1.Router }]; } });
3397
3820
 
3821
+ class ValidatorsModule {
3822
+ }
3823
+ ValidatorsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: ValidatorsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3824
+ ValidatorsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.7", ngImport: i0, type: ValidatorsModule, imports: [CommonModule] });
3825
+ ValidatorsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: ValidatorsModule, providers: [CreditCardMinLengthValidator], imports: [CommonModule] });
3826
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: ValidatorsModule, decorators: [{
3827
+ type: NgModule,
3828
+ args: [{
3829
+ declarations: [],
3830
+ imports: [CommonModule],
3831
+ providers: [CreditCardMinLengthValidator],
3832
+ }]
3833
+ }] });
3834
+
3398
3835
  class FormModule {
3399
3836
  }
3400
3837
  FormModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: FormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3401
- FormModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.7", ngImport: i0, type: FormModule, imports: [ReactiveFormsModule] });
3838
+ FormModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.7", ngImport: i0, type: FormModule, imports: [ReactiveFormsModule, ValidatorsModule] });
3402
3839
  FormModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: FormModule, providers: [
3403
3840
  FormService,
3404
3841
  ControlConfigService,
3405
3842
  ZipConverter,
3406
3843
  EmailConverter,
3844
+ CardNumberConverter,
3407
3845
  { provide: convertersMapToken, useValue: convertersMap },
3408
- ], imports: [ReactiveFormsModule] });
3846
+ ], imports: [ReactiveFormsModule, ValidatorsModule] });
3409
3847
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.7", ngImport: i0, type: FormModule, decorators: [{
3410
3848
  type: NgModule,
3411
3849
  args: [{
3412
- imports: [ReactiveFormsModule],
3850
+ imports: [ReactiveFormsModule, ValidatorsModule],
3413
3851
  providers: [
3414
3852
  FormService,
3415
3853
  ControlConfigService,
3416
3854
  ZipConverter,
3417
3855
  EmailConverter,
3856
+ CardNumberConverter,
3418
3857
  { provide: convertersMapToken, useValue: convertersMap },
3419
3858
  ],
3420
3859
  }]