@everymatrix/general-input 1.87.0 → 1.87.2

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,5 +1,5 @@
1
1
  import { h } from "@stencil/core";
2
- import { translate } from "../../utils/locale.utils";
2
+ import { translate, validateID, CONSTANTS, ERROR_KEYS } from "../../utils/locale.utils";
3
3
  import tooltipIcon from "../../utils/tooltipIcon.svg";
4
4
  export class TextInput {
5
5
  constructor() {
@@ -9,24 +9,28 @@ export class TextInput {
9
9
  this.postalcodelength = 5;
10
10
  this.touched = false;
11
11
  this.handleInput = (event) => {
12
- this.value = event.target.value;
12
+ const input = event.target;
13
+ const normalizedValue = this.enableSouthAfricanMode &&
14
+ (this.name === CONSTANTS.FIRSTNAME_ON_DOCUMENT ||
15
+ this.name === CONSTANTS.LASTNAME_ON_DOCUMENT)
16
+ ? input.value.replace(CONSTANTS.NON_LETTERS_REGEX, '')
17
+ : input.value;
18
+ if (normalizedValue !== input.value) {
19
+ input.value = normalizedValue;
20
+ }
21
+ this.value = normalizedValue;
13
22
  this.touched = true;
14
- if (this.debounceTime) {
23
+ if (this.debounceTime)
15
24
  clearTimeout(this.debounceTime);
16
- }
17
25
  this.debounceTime = setTimeout(() => {
18
- this.isValid = this.setValidity();
19
- this.errorMessage = this.setErrorMessage();
20
- this.validityStateHandler({ valid: this.isValid, name: this.name });
26
+ this.updateValidationState();
21
27
  this.emitValueHandler(true);
22
28
  }, 500);
23
29
  };
24
30
  this.handleBlur = (event) => {
25
31
  this.value = event.target.value;
26
32
  this.touched = true;
27
- this.isValid = this.setValidity();
28
- this.errorMessage = this.setErrorMessage();
29
- this.validityStateHandler({ valid: this.isValid, name: this.name });
33
+ this.updateValidationState();
30
34
  };
31
35
  this.setClientStyling = () => {
32
36
  let sheet = document.createElement('style');
@@ -46,6 +50,7 @@ export class TextInput {
46
50
  this.isDuplicateInput = undefined;
47
51
  this.clientStyling = '';
48
52
  this.haspostalcodelookup = undefined;
53
+ this.enableSouthAfricanMode = undefined;
49
54
  this.isValid = undefined;
50
55
  this.errorMessage = '';
51
56
  this.limitStylingAppends = false;
@@ -83,15 +88,13 @@ export class TextInput {
83
88
  if (this.isDuplicateInput && this.name === event.detail.name + 'Duplicate') {
84
89
  this.duplicateInputValue = event.detail.value;
85
90
  if (this.touched) {
86
- this.isValid = this.setValidity();
87
- this.errorMessage = this.setErrorMessage();
91
+ this.updateValidationState();
88
92
  }
89
93
  }
90
- if (this.name === event.detail.name + 'Duplicate'
91
- && this.name.replace('Duplicate', '') === event.detail.name
92
- && this.touched === true) {
93
- this.isValid = this.setValidity();
94
- this.errorMessage = this.setErrorMessage();
94
+ if (this.name === event.detail.name + 'Duplicate' &&
95
+ this.name.replace('Duplicate', '') === event.detail.name &&
96
+ this.touched) {
97
+ this.updateValidationState();
95
98
  }
96
99
  }
97
100
  handleValidationChange(event) {
@@ -101,7 +104,7 @@ export class TextInput {
101
104
  this.validation = event.detail.validation;
102
105
  this.validationPattern = this.setPattern();
103
106
  if (this.touched) {
104
- this.isValid = this.setValidity();
107
+ this.isValid = this.isValidValue();
105
108
  this.errorMessage = this.setErrorMessage();
106
109
  }
107
110
  }
@@ -137,13 +140,37 @@ export class TextInput {
137
140
  }
138
141
  this.value = newValue;
139
142
  this.touched = true;
140
- this.isValid = true;
141
- this.valueHandler({ name: this.name, value: newValue });
142
- this.validityStateHandler({ valid: true, name: this.name });
143
+ this.updateValidationState();
143
144
  }
144
145
  connectedCallback() {
145
146
  this.validationPattern = this.setPattern();
146
147
  }
148
+ handleExternalDocUpdate(event) {
149
+ if (this.name !== CONSTANTS.DOCUMENT_NUMBER)
150
+ return;
151
+ this.value = event.detail || "";
152
+ this.touched = true;
153
+ if (this.inputReference) {
154
+ this.inputReference.value = this.value;
155
+ }
156
+ this.sendInputValue.emit({
157
+ name: this.name,
158
+ value: this.value
159
+ });
160
+ this.updateValidationState();
161
+ }
162
+ handleDocReset() {
163
+ if (this.name !== CONSTANTS.DOCUMENT_NUMBER)
164
+ return;
165
+ this.value = "";
166
+ this.touched = false;
167
+ this.isValid = false;
168
+ this.errorMessage = "";
169
+ if (this.inputReference) {
170
+ this.inputReference.value = "";
171
+ }
172
+ this.validityStateHandler({ valid: false, name: this.name });
173
+ }
147
174
  componentDidRender() {
148
175
  // start custom styling area
149
176
  if (!this.limitStylingAppends && this.stylingContainer) {
@@ -160,6 +187,7 @@ export class TextInput {
160
187
  }
161
188
  componentDidLoad() {
162
189
  if (this.defaultValue) {
190
+ this.value = this.defaultValue;
163
191
  this.valueHandler({ name: this.name, value: this.value });
164
192
  if (this.isDuplicateInput) {
165
193
  this.touched = true;
@@ -171,18 +199,49 @@ export class TextInput {
171
199
  window.targetInputRefs[this.name] = this.inputReference;
172
200
  }
173
201
  }
174
- this.isValid = this.setValidity();
202
+ this.isValid = this.isValidValue();
203
+ }
204
+ validateDocument(valueRaw, docType) {
205
+ const value = valueRaw.trim();
206
+ if (docType === CONSTANTS.PASSPORT) {
207
+ const valid = CONSTANTS.PASSPORT_NUMERIC_REGEX.test(value);
208
+ return valid
209
+ ? { valid: true }
210
+ : { valid: false, errorKey: ERROR_KEYS.PASSPORT_INVALID };
211
+ }
212
+ if (docType === CONSTANTS.SOUTH_AFRICAN_ID) {
213
+ if (value.length !== CONSTANTS.SOUTH_AFRICAN_ID_LENGTH) {
214
+ return { valid: false, errorKey: ERROR_KEYS.SA_ID_LENGTH };
215
+ }
216
+ const valid = validateID(value);
217
+ return valid
218
+ ? { valid: true }
219
+ : { valid: false, errorKey: ERROR_KEYS.SA_ID_INVALID };
220
+ }
221
+ return { valid: true };
175
222
  }
176
- setValidity() {
223
+ updateValidationState() {
224
+ const nextValid = this.isValidValue();
225
+ this.isValid = nextValid;
226
+ if (!this.touched) {
227
+ this.errorMessage = '';
228
+ return;
229
+ }
230
+ this.errorMessage = nextValid ? '' : this.setErrorMessage();
231
+ }
232
+ isValidValue() {
177
233
  if (!this.inputReference) {
178
234
  return false;
179
235
  }
180
- if (this.value.trim() === "" && !this.validation.mandatory) {
181
- return true;
236
+ if (this.enableSouthAfricanMode && this.name === CONSTANTS.DOCUMENT_NUMBER) {
237
+ const docType = window.documentTypeValue;
238
+ return this.validateDocument(this.value, docType).valid;
182
239
  }
183
- const inputIsValid = this.inputReference.validity.valid;
184
- const inputMatchValidation = !this.inputReference.value || this.inputReference.value.match(this.validationPattern) !== null;
185
- return inputIsValid && inputMatchValidation;
240
+ const fallbackResult = (this.value.trim() === "" && !this.validation.mandatory) ||
241
+ (this.inputReference.validity.valid &&
242
+ (!this.inputReference.value ||
243
+ this.inputReference.value.match(this.validationPattern) !== null));
244
+ return fallbackResult;
186
245
  }
187
246
  setPattern() {
188
247
  var _a, _b;
@@ -192,14 +251,25 @@ export class TextInput {
192
251
  }
193
252
  setErrorMessage() {
194
253
  var _a, _b, _c, _d;
195
- if (this.value.trim() === "" && !this.validation.mandatory) {
254
+ const value = this.value.trim();
255
+ if (this.enableSouthAfricanMode && this.name === CONSTANTS.DOCUMENT_NUMBER) {
256
+ const docType = window.documentTypeValue;
257
+ const res = this.validateDocument(this.value, docType);
258
+ return res.valid ? '' : translate(res.errorKey, this.language);
259
+ }
260
+ if (value === "" && !this.validation.mandatory) {
196
261
  return "";
197
262
  }
198
263
  if (this.inputReference.validity.valueMissing) {
199
- return translate('requiredError', this.language);
264
+ return translate(ERROR_KEYS.REQUIRED, this.language);
200
265
  }
201
266
  if (this.inputReference.validity.tooShort || this.inputReference.validity.tooLong) {
202
- return translate('lengthError', this.language, { values: { minLength: this.validation.minLength, maxLength: this.validation.maxLength } });
267
+ return translate(ERROR_KEYS.LENGTH, this.language, {
268
+ values: {
269
+ minLength: this.validation.minLength,
270
+ maxLength: this.validation.maxLength
271
+ }
272
+ });
203
273
  }
204
274
  if (this.inputReference.value.match(this.validationPattern) == null) {
205
275
  const errorCode = (_a = this.validation.custom.find(customValidation => customValidation.rule === 'regex')) === null || _a === void 0 ? void 0 : _a.errorKey;
@@ -211,6 +281,7 @@ export class TextInput {
211
281
  const errorMessage = (_d = this.validation.custom.find(customRule => customRule.rule === 'duplicate-input')) === null || _d === void 0 ? void 0 : _d.errorMessage;
212
282
  return translate(`${errorCode}`, this.language) ? translate(`${errorCode}`, this.language) : errorMessage;
213
283
  }
284
+ return "";
214
285
  }
215
286
  renderTooltip() {
216
287
  if (this.showTooltip) {
@@ -223,8 +294,8 @@ export class TextInput {
223
294
  if (this.touched) {
224
295
  invalidClass = this.isValid == true || this.isValid == undefined ? '' : 'text__input--invalid';
225
296
  }
226
- return h("div", { key: '46152e946f6a45c2bb07ee07c43bcf356f3cfa29', class: `text__wrapper ${this.name}__input ${this.autofilled ? 'text__wrapper--autofilled' : ''}`, ref: el => this.stylingContainer = el }, h("div", { key: 'f584f23ee97b9a1d23862ec746366d5f00c56552', class: 'text__wrapper--flex' }, h("label", { key: 'ed9fe368bd00151d8b3e43daf148632cfe7d32ff', class: `text__label ${this.validation.mandatory ? 'text__label--required' : ''}`, htmlFor: `${this.name}__input` }, this.displayName), h("div", { key: '01cd5f7321d78422049c45b1816801eca74d2b4d', class: 'text__wrapper--relative' }, this.tooltip &&
227
- h("img", { key: '403689aa01575770be4296aaef0c7846e496d6a7', class: 'text__tooltip-icon', src: tooltipIcon, alt: "", ref: (el) => this.tooltipIconReference = el, onClick: () => this.showTooltip = !this.showTooltip }), this.renderTooltip())), h("input", { key: '5ec8443fd428ea00b9add243ea74e61fbd5b283a', name: this.name, id: `${this.name}__input`, value: this.value, type: 'text', class: `text__input ${invalidClass}`, placeholder: `${this.placeholder}`, ref: (el) => this.inputReference = el, readOnly: this.autofilled, required: this.validation.mandatory, minlength: this.validation.minLength, maxlength: this.validation.maxLength, onInput: this.handleInput, onBlur: this.handleBlur }), h("small", { key: 'd1eb4cf6ac28fff4664a56e27c9f2a21d72b0d61', class: 'text__error-message' }, this.errorMessage));
297
+ return h("div", { key: '5b0bf10acadab5c3362d185cef10c5ed4f3a6a47', class: `text__wrapper ${this.name}__input ${this.autofilled ? 'text__wrapper--autofilled' : ''}`, ref: el => this.stylingContainer = el }, h("div", { key: '6d79cc845aac8d9b11737d35571680d7701c4b94', class: 'text__wrapper--flex' }, h("label", { key: 'de687661fa037d691fe1da1231b651f564bca010', class: `text__label ${this.validation.mandatory ? 'text__label--required' : ''}`, htmlFor: `${this.name}__input` }, this.displayName), h("div", { key: '4d9b12a587267eaf6fab4c4f3c38befb8d5c2b99', class: 'text__wrapper--relative' }, this.tooltip &&
298
+ h("img", { key: '7f27a118124cd0407b6c2644137a79eaa0496164', class: 'text__tooltip-icon', src: tooltipIcon, alt: "", ref: (el) => this.tooltipIconReference = el, onClick: () => this.showTooltip = !this.showTooltip }), this.renderTooltip())), h("input", { key: '94a614815155465dbfef2a7cc1cb788bb14d1498', name: this.name, id: `${this.name}__input`, value: this.value, type: 'text', class: `text__input ${invalidClass}`, placeholder: `${this.placeholder}`, ref: (el) => this.inputReference = el, readOnly: this.autofilled, required: this.validation.mandatory, minlength: this.enableSouthAfricanMode ? '' : this.validation.minLength, maxlength: this.enableSouthAfricanMode ? '' : this.validation.maxLength, onInput: this.handleInput, onBlur: this.handleBlur }), h("small", { key: 'b9b3bdcd9cb81b56dc25a208b0c1d7784d06b5e0', class: 'text__error-message' }, this.errorMessage));
228
299
  }
229
300
  static get is() { return "text-input"; }
230
301
  static get encapsulation() { return "shadow"; }
@@ -466,6 +537,23 @@ export class TextInput {
466
537
  },
467
538
  "attribute": "haspostalcodelookup",
468
539
  "reflect": true
540
+ },
541
+ "enableSouthAfricanMode": {
542
+ "type": "boolean",
543
+ "mutable": false,
544
+ "complexType": {
545
+ "original": "boolean",
546
+ "resolved": "boolean",
547
+ "references": {}
548
+ },
549
+ "required": false,
550
+ "optional": false,
551
+ "docs": {
552
+ "tags": [],
553
+ "text": "Enable South African registration mode"
554
+ },
555
+ "attribute": "enable-south-african-mode",
556
+ "reflect": true
469
557
  }
470
558
  };
471
559
  }
@@ -566,6 +654,18 @@ export class TextInput {
566
654
  "target": "body",
567
655
  "capture": false,
568
656
  "passive": false
657
+ }, {
658
+ "name": "documentNumberUpdatedExternally",
659
+ "method": "handleExternalDocUpdate",
660
+ "target": "window",
661
+ "capture": false,
662
+ "passive": false
663
+ }, {
664
+ "name": "documentNumberResetValidation",
665
+ "method": "handleDocReset",
666
+ "target": "window",
667
+ "capture": false,
668
+ "passive": false
569
669
  }];
570
670
  }
571
671
  }
@@ -58,20 +58,24 @@ export class TwofaInput {
58
58
  this.handleInput = (e, idx) => {
59
59
  const input = e.target;
60
60
  const value = input.value;
61
- if (value.length > 1) {
62
- input.value = value.charAt(1);
63
- }
64
- else {
65
- input.value = value.charAt(0);
66
- }
67
- if (!value) {
61
+ const char = value.slice(-1);
62
+ input.value = char;
63
+ if (!char)
68
64
  return;
65
+ this.code[idx] = char;
66
+ // --- Hide pin code --- //
67
+ if (this.enableSouthAfricanMode) {
68
+ // show character for 500ms
69
+ this.revealedIndexes = [idx];
70
+ if (this.revealTimeout)
71
+ clearTimeout(this.revealTimeout);
72
+ this.revealTimeout = setTimeout(() => {
73
+ this.revealedIndexes = [];
74
+ }, 500);
69
75
  }
70
- this.code[idx] = input.value;
71
76
  const nextInput = this.inputRefs[idx + 1];
72
- if (nextInput) {
77
+ if (nextInput)
73
78
  nextInput.focus();
74
- }
75
79
  this.setValidity();
76
80
  this.setErrorMessage();
77
81
  };
@@ -100,6 +104,8 @@ export class TwofaInput {
100
104
  this.destination = '';
101
105
  this.resendIntervalSeconds = 60;
102
106
  this.clientStyling = '';
107
+ this.enableSouthAfricanMode = undefined;
108
+ this.pinAttemptsExceeded = undefined;
103
109
  this.clientStylingUrl = '';
104
110
  this.mbSource = undefined;
105
111
  this.limitStylingAppends = false;
@@ -109,10 +115,7 @@ export class TwofaInput {
109
115
  this.errorMessage = '';
110
116
  this.code = [];
111
117
  this.resendIntervalSecondsLeft = this.resendIntervalSeconds;
112
- }
113
- handleStylingChange(newValue, oldValue) {
114
- if (newValue !== oldValue)
115
- this.setClientStyling();
118
+ this.revealedIndexes = [];
116
119
  }
117
120
  validityChanged() {
118
121
  this.validityStateHandler({ valid: this.isValid, name: this.name });
@@ -141,6 +144,10 @@ export class TwofaInput {
141
144
  this.showTooltip = false;
142
145
  }
143
146
  }
147
+ handleStylingChange(newValue, oldValue) {
148
+ if (newValue !== oldValue)
149
+ this.setClientStyling();
150
+ }
144
151
  connectedCallback() {
145
152
  this.validationPattern = this.setPattern();
146
153
  this.code = new Array(this.validation.maxLength).fill('');
@@ -175,37 +182,51 @@ export class TwofaInput {
175
182
  }
176
183
  handleKeyDown(e, idx) {
177
184
  if (e.key === 'Backspace') {
178
- this.code[idx] = '';
179
- if (this.inputRefs[idx]) {
180
- this.inputRefs[idx].value = '';
181
- } // Clear input field
182
- const prevInput = this.inputRefs[idx - 1];
183
- if (prevInput) {
184
- prevInput === null || prevInput === void 0 ? void 0 : prevInput.focus();
185
+ const newCode = [...this.code];
186
+ newCode[idx] = '';
187
+ this.code = newCode;
188
+ if (this.enableSouthAfricanMode) {
189
+ this.revealedIndexes = this.revealedIndexes.filter(i => i !== idx);
185
190
  }
191
+ const prevInput = this.inputRefs[idx - 1];
192
+ prevInput === null || prevInput === void 0 ? void 0 : prevInput.focus();
186
193
  }
187
194
  this.setValidity();
188
195
  this.setErrorMessage();
189
196
  }
190
197
  handlePaste(e) {
191
- var _a;
198
+ var _a, _b;
192
199
  e.preventDefault();
193
- const data = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text').trim();
194
- if (!data) {
200
+ const data = (_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text')) === null || _b === void 0 ? void 0 : _b.trim();
201
+ if (!data)
195
202
  return;
203
+ const value = data.slice(0, this.validation.maxLength).split('');
204
+ this.code = [
205
+ ...value,
206
+ ...new Array(this.validation.maxLength - value.length).fill('')
207
+ ];
208
+ if (this.enableSouthAfricanMode) {
209
+ this.revealedIndexes = value.map((_, i) => i);
210
+ if (this.revealTimeout)
211
+ clearTimeout(this.revealTimeout);
212
+ this.revealTimeout = setTimeout(() => {
213
+ this.revealedIndexes = [];
214
+ }, 500);
196
215
  }
197
- const value = data.slice(0, this.validation.maxLength).split(''); // Limit to OTP length
198
- this.code = [...value, ...new Array(this.validation.maxLength - value.length).fill('')];
199
- value.forEach((char, index) => {
200
- this.inputRefs[index].value = char;
201
- });
202
- // Move focus to the last input or trigger submit
203
216
  const lastInput = this.inputRefs[Math.min(value.length, this.inputRefs.length - 1)];
204
- if (lastInput) {
205
- lastInput.focus();
206
- }
217
+ lastInput === null || lastInput === void 0 ? void 0 : lastInput.focus();
207
218
  this.setValidity();
208
219
  this.setErrorMessage();
220
+ if (this.enableSouthAfricanMode) {
221
+ this.valueHandler({
222
+ name: this.name,
223
+ value: this.code.join('')
224
+ });
225
+ this.validityStateHandler({
226
+ valid: this.isValid,
227
+ name: this.name
228
+ });
229
+ }
209
230
  }
210
231
  setValidity() {
211
232
  const code = this.code.join('');
@@ -238,10 +259,19 @@ export class TwofaInput {
238
259
  }
239
260
  return null;
240
261
  }
262
+ getInputDisplayValue(idx) {
263
+ const current = this.code[idx];
264
+ if (!current)
265
+ return "";
266
+ if (this.enableSouthAfricanMode) {
267
+ return this.revealedIndexes.includes(idx) ? current : "*";
268
+ }
269
+ return current;
270
+ }
241
271
  render() {
242
- return (h("div", { key: '45f0c8c7d88898a5474bff460ce962e8bb1e8634', class: "twofa", ref: el => this.stylingContainer = el }, h("div", { key: 'b40e81587ad9c7b67c112c8867104e761db7e3bc', class: 'twofa__error-message' }, h("p", { key: '760c694f6f71f040e85f81a67d3d41524c23130f' }, this.errorMessage)), h("div", { key: '2b437a5108e3989d2ddf596dc4a97d2071448154', class: "twofa__description", innerHTML: translate('twofaDescription', this.language, { values: { destination: this.destination } }) }), h("div", { key: '84df3ebbe4077ba8462c08cc7956349ec4a55b79', class: "twofa__input-wrapper", ref: this.setContainerRef }, this.code.map((char, idx) => {
243
- return (h("input", { key: idx, ref: el => this.setInputRef(el, idx), id: `otp-input-${idx}`, type: "text", maxLength: 2, value: char, onInput: (event) => this.handleInput(event, idx), onKeyDown: (event) => this.handleKeyDown(event, idx), onPaste: (event) => this.handlePaste(event) }));
244
- })), h("div", { key: 'abdf6e2a3ff7ef6436b59206c40ada5305543db3', class: "twofa__button-wrapper" }, h("p", { key: 'e0859c58e48741eb379fbcaf23519bb90404489b', class: "twofa__resend-message" }, translate('twofaResendMessage', this.language)), h("button", { key: '89aa3a93a9b97029fd315450892cef5edd5d5294', class: "twofa__resend-button", onClick: this.resendCodeHandler, disabled: !this.isResendButtonAvailable }, this.isResendButtonAvailable
272
+ return (h("div", { key: '56a639eb6e240482078fc7aaf688c75ae3de04c8', class: "twofa", ref: el => this.stylingContainer = el }, h("div", { key: 'a64039a3ed66556a0dc1bbac7b6fd6d60de23fa3', class: 'twofa__error-message' }, h("p", { key: '21adf57c840d51714ab097e9df3cc77e22be611f' }, this.errorMessage)), h("div", { key: '6653201178b40bc1eb5d6e7d881f2bbe150901f3', class: "twofa__description", innerHTML: translate('twofaDescription', this.language, { values: { destination: this.destination } }) }), h("div", { key: 'ca7600034af473838b741d5be4fe72ded9937647', class: "twofa__input-wrapper", ref: this.setContainerRef }, this.code.map((_, idx) => {
273
+ return (h("input", { key: idx, ref: el => this.setInputRef(el, idx), id: `otp-input-${idx}`, type: "text", maxLength: 2, value: this.getInputDisplayValue(idx), onInput: (event) => this.handleInput(event, idx), onKeyDown: (event) => this.handleKeyDown(event, idx), onPaste: (event) => this.handlePaste(event) }));
274
+ })), h("div", { key: '0ecd60dd5e6b3f6c3a86176e1937e7aeeffc0e92', class: "twofa__button-wrapper" }, h("p", { key: 'fa9608598580bb8628d0e7a208cc69e3ebe83264', class: "twofa__resend-message" }, translate('twofaResendMessage', this.language)), h("button", { key: 'c70ea6e780eefc8fef0002fdcc10286ae0e66619', class: `twofa__resend-button ${this.pinAttemptsExceeded ? 'twofa__resend-button--disabled' : ''}`, onClick: this.resendCodeHandler, disabled: !this.isResendButtonAvailable || this.pinAttemptsExceeded }, this.isResendButtonAvailable
245
275
  ? translate('twofaResendButton', this.language)
246
276
  : this.formatTime()))));
247
277
  }
@@ -442,6 +472,40 @@ export class TwofaInput {
442
472
  "reflect": true,
443
473
  "defaultValue": "''"
444
474
  },
475
+ "enableSouthAfricanMode": {
476
+ "type": "boolean",
477
+ "mutable": false,
478
+ "complexType": {
479
+ "original": "boolean",
480
+ "resolved": "boolean",
481
+ "references": {}
482
+ },
483
+ "required": false,
484
+ "optional": false,
485
+ "docs": {
486
+ "tags": [],
487
+ "text": "Enable South African registration mode"
488
+ },
489
+ "attribute": "enable-south-african-mode",
490
+ "reflect": true
491
+ },
492
+ "pinAttemptsExceeded": {
493
+ "type": "boolean",
494
+ "mutable": false,
495
+ "complexType": {
496
+ "original": "boolean",
497
+ "resolved": "boolean",
498
+ "references": {}
499
+ },
500
+ "required": false,
501
+ "optional": false,
502
+ "docs": {
503
+ "tags": [],
504
+ "text": "Check if user has exceeded the failing pin code inputs"
505
+ },
506
+ "attribute": "pin-attempts-exceeded",
507
+ "reflect": true
508
+ },
445
509
  "clientStylingUrl": {
446
510
  "type": "string",
447
511
  "mutable": false,
@@ -487,7 +551,8 @@ export class TwofaInput {
487
551
  "showTooltip": {},
488
552
  "errorMessage": {},
489
553
  "code": {},
490
- "resendIntervalSecondsLeft": {}
554
+ "resendIntervalSecondsLeft": {},
555
+ "revealedIndexes": {}
491
556
  };
492
557
  }
493
558
  static get events() {
@@ -568,9 +633,6 @@ export class TwofaInput {
568
633
  static get elementRef() { return "host"; }
569
634
  static get watchers() {
570
635
  return [{
571
- "propName": "clientStyling",
572
- "methodName": "handleStylingChange"
573
- }, {
574
636
  "propName": "isValid",
575
637
  "methodName": "validityChanged"
576
638
  }, {
@@ -579,6 +641,9 @@ export class TwofaInput {
579
641
  }, {
580
642
  "propName": "clientStylingUrl",
581
643
  "methodName": "handleStylingUrlChange"
644
+ }, {
645
+ "propName": "clientStyling",
646
+ "methodName": "handleStylingChange"
582
647
  }];
583
648
  }
584
649
  static get listeners() {
@@ -29,6 +29,10 @@ export const TRANSLATIONS = {
29
29
  "enterIEAddressManually": "For IRE, enter the address manually",
30
30
  "postalLookUpNoAddressFound": "No addresses found for this postal code",
31
31
  "searchingForAddresses": "Searching for addresses...",
32
+ "SAIdLengthError": "SA ID must be 13 digits",
33
+ "SAIdInvalidError": "Invalid SA ID",
34
+ "PassportLengthError": "Passport number must be 8 or 9 digits.",
35
+ "PasswordMustContain": "Password must contain:"
32
36
  },
33
37
  "hu": {
34
38
  "dateError": "A választott dátumnak {min} és {max} között kell lennie",
@@ -55,7 +59,11 @@ export const TRANSLATIONS = {
55
59
  "InvalidDocumentNumber": "Csak számjegyek engedélyezettek.",
56
60
  "twofaDescription": "<p> A megerősítő kódot elküldtük a következő címre: <p> {destination}. </p> </p> <p> Kérjük, írja be az alábbi PIN-kódot. </p>",
57
61
  "twofaResendMessage": "Nem kapta meg a megerősítő kódot?",
58
- "twofaResendButton": "Újraküldés"
62
+ "twofaResendButton": "Újraküldés",
63
+ "PassportLengthError": "Az útlevélszámnak 9 számjegyűnek kell lennie",
64
+ "SAIdLengthError": "A dél-afrikai személyi számnak 13 számjegyűnek kell lennie",
65
+ "SAIdInvalidError": "Érvénytelen dél-afrikai személyi szám",
66
+ "PasswordMustContain": "A jelszónak tartalmaznia kell:"
59
67
  },
60
68
  "hr": {
61
69
  "dateError": "Odabrani datum treba biti između {min} i {max}",
@@ -82,7 +90,11 @@ export const TRANSLATIONS = {
82
90
  "InvalidDocumentNumber": "Dopušteni su samo numerički znakovi.",
83
91
  "twofaDescription": "<p> Poslali smo verifikacijski kod na: <p> {destination}. </p> </p> <p> Molimo unesite PIN ispod. </p>",
84
92
  "twofaResendMessage": "Niste primili verifikacijski kod?",
85
- "twofaResendButton": "Ponovno pošalji"
93
+ "twofaResendButton": "Ponovno pošalji",
94
+ "PassportLengthError": "Broj putovnice mora imati 9 znamenki",
95
+ "SAIdLengthError": "Južnoafrički osobni broj mora imati 13 znamenki",
96
+ "SAIdInvalidError": "Nevažeći južnoafrički osobni broj",
97
+ "PasswordMustContain": "Lozinka mora sadržavati:"
86
98
  },
87
99
  "tr": {
88
100
  "dateError": "Seçilen tarih {min} ve {max} arasında olmalıdır",
@@ -109,7 +121,11 @@ export const TRANSLATIONS = {
109
121
  "InvalidDocumentNumber": "Sadece sayısal karakterlere izin verilir.",
110
122
  "twofaDescription": "<p> Doğrulama kodunu şu adrese gönderdik: <p> {destination}. </p> </p> <p> Lütfen aşağıya PIN kodunu girin. </p>",
111
123
  "twofaResendMessage": "Doğrulama kodunu almadınız mı?",
112
- "twofaResendButton": "Yeniden gönder"
124
+ "twofaResendButton": "Yeniden gönder",
125
+ "PassportLengthError": "Pasaport numarası 9 haneli olmalıdır",
126
+ "SAIdLengthError": "Güney Afrika kimlik numarası 13 haneli olmalıdır",
127
+ "SAIdInvalidError": "Geçersiz Güney Afrika kimlik numarası",
128
+ "PasswordMustContain": "Şifre şunları içermelidir:"
113
129
  },
114
130
  "pt-br": {
115
131
  "dateError": "A data selecionada deve estar entre {min} e {max}",
@@ -136,7 +152,11 @@ export const TRANSLATIONS = {
136
152
  "InvalidDocumentNumber": "Apenas caracteres numéricos são permitidos.",
137
153
  "twofaDescription": "<p> Enviamos o código de verificação para: <p> {destination}. </p> </p> <p> Por favor, insira o PIN abaixo. </p>",
138
154
  "twofaResendMessage": "Não recebeu o código de verificação?",
139
- "twofaResendButton": "Reenviar"
155
+ "twofaResendButton": "Reenviar",
156
+ "PassportLengthError": "O número do passaporte deve ter 9 dígitos",
157
+ "SAIdLengthError": "O número de identificação da África do Sul deve ter 13 dígitos",
158
+ "SAIdInvalidError": "Número de identificação da África do Sul inválido",
159
+ "PasswordMustContain": "A senha deve conter:"
140
160
  },
141
161
  "es-mx": {
142
162
  "dateError": "La fecha seleccionada debe ser entre {min} y {max}",
@@ -163,9 +183,40 @@ export const TRANSLATIONS = {
163
183
  "InvalidDocumentNumber": "Solo se permiten caracteres numéricos.",
164
184
  "twofaDescription": "<p> Hemos enviado el código de verificación a: <p> {destination}. </p> </p> <p> Por favor, ingrese el PIN a continuación. </p>",
165
185
  "twofaResendMessage": "¿No recibiste el código de verificación?",
166
- "twofaResendButton": "Reenviar"
186
+ "twofaResendButton": "Reenviar",
187
+ "PassportLengthError": "El número de pasaporte debe tener 9 dígitos",
188
+ "SAIdLengthError": "El número de identificación de Sudáfrica debe tener 13 dígitos",
189
+ "SAIdInvalidError": "Número de identificación de Sudáfrica inválido",
190
+ "PasswordMustContain": "La contraseña debe contener:"
167
191
  }
168
192
  };
193
+ export const CONSTANTS = {
194
+ DOCUMENT_NUMBER: "DocumentNumber",
195
+ FIRSTNAME_ON_DOCUMENT: "FirstnameOnDocument",
196
+ LASTNAME_ON_DOCUMENT: "LastnameOnDocument",
197
+ PASSPORT: "Passport",
198
+ SOUTH_AFRICAN_ID: "SouthAfricanID",
199
+ BIRTHDATE: "BirthDate",
200
+ PASSPORT_NUMERIC_REGEX: /^\d{8,9}$/,
201
+ SA_ID_BASIC_REGEX: /^\d{13}$/,
202
+ SOUTH_AFRICAN_ID_LENGTH: 13,
203
+ NON_LETTERS_REGEX: /[^A-Za-z]/g,
204
+ DATE_FORMAT: "yyyy-MM-dd",
205
+ PASSWORD_COMPLEXITY_PASSED: "passed",
206
+ PASSWORD_COMPLEXITY_FAILED: "failed"
207
+ };
208
+ export const ERROR_KEYS = {
209
+ PASSPORT_INVALID: 'PassportLengthError',
210
+ SA_ID_LENGTH: 'SAIdLengthError',
211
+ SA_ID_INVALID: 'SAIdInvalidError',
212
+ REQUIRED: 'requiredError',
213
+ LENGTH: 'lengthError',
214
+ DUPLICATE: 'duplicateInputError',
215
+ };
216
+ export const STATUS_ICONS = {
217
+ PASSED: '✓',
218
+ FAILED: '✕',
219
+ };
169
220
  export const translate = (key, customLang, values) => {
170
221
  const lang = customLang;
171
222
  let translation = TRANSLATIONS[lang !== undefined ? lang : DEFAULT_LANGUAGE][key];
@@ -192,3 +243,24 @@ export const getTranslations = (url) => {
192
243
  });
193
244
  });
194
245
  };
246
+ export const validateID = (id) => {
247
+ if (!CONSTANTS.SA_ID_BASIC_REGEX.test(id))
248
+ return false;
249
+ const digits = id.split("").map(n => parseInt(n, 10));
250
+ let oddSum = 0;
251
+ for (let i = 0; i < 12; i += 2) {
252
+ oddSum += digits[i];
253
+ }
254
+ let evenConcat = "";
255
+ for (let i = 1; i < 12; i += 2) {
256
+ evenConcat += digits[i];
257
+ }
258
+ const evenNumber = parseInt(evenConcat, 10) * 2;
259
+ const evenSum = evenNumber
260
+ .toString()
261
+ .split("")
262
+ .reduce((s, n) => s + parseInt(n, 10), 0);
263
+ const total = oddSum + evenSum;
264
+ let checkDigit = (10 - (total % 10)) % 10;
265
+ return checkDigit === digits[12];
266
+ };