@hellotext/hellotext 1.7.0 → 1.7.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.
package/docs/forms.md CHANGED
@@ -79,15 +79,28 @@ This will mount the form regardless if the user has completed the form or not.
79
79
 
80
80
  Hellotext automatically validates the form inputs based on how they were configured on the dashboard
81
81
  using browser's native [checkValidity()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/checkValidity).
82
+
82
83
  Once the user tries to submit the form and there are missing required fields,
83
84
  the submission is halted and we display default browser's error message using [HTMLObjectElement.validationMessage](https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage) property.
84
85
 
85
- ### Authentication
86
+ If the form contains a unique property and the client enters a value that is already taken,
87
+ the submission will not be complete. Instead, an error will be reported to the client and the form will not be submitted.
88
+
89
+ Uniqueness errors use the browser's native [setCustomValidity()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/setCustomValidity)
90
+ method which are reported as normal form validation errors, they can be styled with the `input:invalid` selector.
91
+
92
+ ### Understanding Verification
86
93
 
87
94
  Hellotext protects you from bot submissions and protects your customers from identity theft and impersonation.
88
- When a subscriber fills the form, Hellotext sends a One Time Password (OTP) code to the subscriber. If they have an email,
89
- an email is sent to them, otherwise an SMS is sent to their phone number.
90
- Until a valid OTP has been entered, data will not show up on the dashboard and will not contribute to attribution marketing.
95
+
96
+ When a subscriber fills the form with an email and/or phone number, Hellotext sends a verification link to the value the submission had at the time of creation.
97
+ When the customer clicks the link in their email and/or the SMS they receive, the attribute is verified.
98
+ Once the email/phone number were verified, the data is considered to be _verified_.
99
+
100
+ Once verification of a submission is complete, Hellotext performs an automatic merge (if needed) of all profiles
101
+ that have the same email and/or phone number. After automatic merging, if a property has multiple values,
102
+ it will be visible in the Audience page and the user can see the values that were merged and they can decide which one
103
+ to ignore and which one to accept.
91
104
 
92
105
  ### Form Completion
93
106
 
@@ -8,7 +8,6 @@ var _stimulus = require("@hotwired/stimulus");
8
8
  var _hellotext = _interopRequireDefault(require("../hellotext"));
9
9
  var _models = require("../models");
10
10
  var _forms = _interopRequireDefault(require("../api/forms"));
11
- var _otp_builder = require("../builders/otp_builder");
12
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
12
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
14
13
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
@@ -60,30 +59,35 @@ var _default = /*#__PURE__*/function (_Controller) {
60
59
  this.buttonTarget.disabled = true;
61
60
  var response = yield _forms.default.submit(this.form.id, this.formData);
62
61
  this.buttonTarget.disabled = false;
62
+ var data = yield response.json();
63
63
  if (response.failed) {
64
- return;
64
+ data.errors.forEach(error => {
65
+ var {
66
+ type,
67
+ parameter
68
+ } = error;
69
+ var input = this.inputTargets.find(input => input.name === parameter);
70
+ input.setCustomValidity(_hellotext.default.business.locale.errors[type]);
71
+ input.reportValidity();
72
+ input.addEventListener('input', () => {
73
+ input.setCustomValidity('');
74
+ input.reportValidity();
75
+ });
76
+ });
77
+ return this.showErrorMessages();
65
78
  }
66
79
  this.buttonTarget.style.display = 'none';
67
80
  this.element.querySelectorAll('input').forEach(input => input.disabled = true);
68
- var submission = yield response.json();
69
- if (submission.identified) {
70
- this.completed();
71
- } else {
72
- _hellotext.default.setSession(submission.session);
73
- this.revealOTPContainer(submission.id);
81
+ if (!data.identified) {
82
+ _hellotext.default.setSession(data.session);
74
83
  }
84
+ this.completed();
75
85
  });
76
86
  function submit(_x) {
77
87
  return _submit.apply(this, arguments);
78
88
  }
79
89
  return submit;
80
90
  }()
81
- }, {
82
- key: "revealOTPContainer",
83
- value: function revealOTPContainer(submissionId) {
84
- var paragraph = this.requiredInputs.find(input => input.name === 'email') ? _hellotext.default.business.locale.otp.sent_to_email : _hellotext.default.business.locale.otp.sent_to_phone;
85
- this.element.appendChild(_otp_builder.OTPBuilder.build(submissionId, paragraph));
86
- }
87
91
  }, {
88
92
  key: "completed",
89
93
  value: function completed() {
@@ -104,6 +108,7 @@ var _default = /*#__PURE__*/function (_Controller) {
104
108
  key: "clearErrorMessages",
105
109
  value: function clearErrorMessages() {
106
110
  this.element.querySelectorAll('input').forEach(input => {
111
+ input.setCustomValidity('');
107
112
  var parent = input.closest('article');
108
113
  parent.querySelector('[data-error-container]').innerText = '';
109
114
  });
package/lib/hellotext.js CHANGED
@@ -23,12 +23,11 @@ function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototy
23
23
  var id = 0;
24
24
  function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; }
25
25
  var _session = /*#__PURE__*/_classPrivateFieldLooseKey("session");
26
- var _config = /*#__PURE__*/_classPrivateFieldLooseKey("config");
27
26
  var _query = /*#__PURE__*/_classPrivateFieldLooseKey("query");
28
27
  var _mintAnonymousSession = /*#__PURE__*/_classPrivateFieldLooseKey("mintAnonymousSession");
29
28
  /**
30
29
  * @typedef {Object} Config
31
- * @property {Boolean} autogenerateSession
30
+ * @property {Boolean} autoGenerateSession
32
31
  * @property {Boolean} autoMountForms
33
32
  */
34
33
  var Hellotext = /*#__PURE__*/function () {
@@ -44,14 +43,14 @@ var Hellotext = /*#__PURE__*/function () {
44
43
  * @param { Config } config
45
44
  */
46
45
  function initialize(business, config) {
47
- _classPrivateFieldLooseBase(this, _config)[_config] = _core.Configuration.assign(config);
46
+ _core.Configuration.assign(config);
48
47
  _classPrivateFieldLooseBase(this, _query)[_query] = new _models.Query();
49
48
  this.business = new _models.Business(business);
50
49
  this.forms = new _models.FormCollection();
51
50
  if (_classPrivateFieldLooseBase(this, _query)[_query].inPreviewMode) return;
52
51
  if (_classPrivateFieldLooseBase(this, _query)[_query].session) {
53
52
  _classPrivateFieldLooseBase(this, _session)[_session] = _models.Cookies.set('hello_session', _classPrivateFieldLooseBase(this, _query)[_query].session);
54
- } else if (config.autogenerateSession) {
53
+ } else if (_core.Configuration.autoGenerateSession) {
55
54
  _classPrivateFieldLooseBase(this, _mintAnonymousSession)[_mintAnonymousSession]().then(response => {
56
55
  _classPrivateFieldLooseBase(this, _session)[_session] = _models.Cookies.set('hello_session', response.id);
57
56
  });
@@ -178,10 +177,6 @@ Object.defineProperty(Hellotext, _session, {
178
177
  writable: true,
179
178
  value: void 0
180
179
  });
181
- Object.defineProperty(Hellotext, _config, {
182
- writable: true,
183
- value: void 0
184
- });
185
180
  Object.defineProperty(Hellotext, _query, {
186
181
  writable: true,
187
182
  value: void 0
package/lib/index.js CHANGED
@@ -7,12 +7,10 @@ exports.default = void 0;
7
7
  var _stimulus = require("@hotwired/stimulus");
8
8
  var _hellotext = _interopRequireDefault(require("./hellotext"));
9
9
  var _form_controller = _interopRequireDefault(require("./controllers/form_controller"));
10
- var _otp_controller = _interopRequireDefault(require("./controllers/otp_controller"));
11
10
  require("../styles/index.css");
12
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
12
  var application = _stimulus.Application.start();
14
13
  application.register('hellotext--form', _form_controller.default);
15
- application.register('hellotext--otp', _otp_controller.default);
16
14
  window.Hellotext = _hellotext.default;
17
15
  var _default = _hellotext.default;
18
16
  exports.default = _default;
package/lib/locales/en.js CHANGED
@@ -5,18 +5,12 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _default = {
8
- otp: {
9
- sent_to_email: 'A One-Time Password has been sent to your email address',
10
- sent_to_phone: 'An One-Time Password has been sent to your phone number',
11
- resend_successful: 'The One-Time Password has been resent successfully',
12
- invalid: 'Invalid One-Time Password',
13
- resend: 'Resend verification code',
14
- submit: 'Submit',
15
- throttled: 'You have reached the maximum number of attempts. Please try again in 1 minute.',
16
- placeholder: 'Enter the code here'
17
- },
18
8
  white_label: {
19
9
  powered_by: 'Powered by'
10
+ },
11
+ errors: {
12
+ parameter_not_unique: 'This value is taken.',
13
+ blank: 'This field is required.'
20
14
  }
21
15
  };
22
16
  exports.default = _default;
package/lib/locales/es.js CHANGED
@@ -5,18 +5,12 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _default = {
8
- otp: {
9
- sent_to_email: 'Un código de un solo uso ha sido enviado a tu correo electrónico',
10
- sent_to_phone: 'Un código de un solo uso ha sido enviado a tu número de teléfono',
11
- resend_successful: 'El código de un solo uso ha sido reenviado exitosamente',
12
- invalid: 'Código de un solo uso inválido',
13
- resend: 'Reenviar código de verificación',
14
- submit: 'Enviar',
15
- throttled: 'Has alcanzado el número máximo de intentos. Por favor intenta de nuevo en 1 minuto.',
16
- placeholder: 'Ingresa el código aquí'
17
- },
18
8
  white_label: {
19
9
  powered_by: 'Desarrollado por'
10
+ },
11
+ errors: {
12
+ parameter_not_unique: 'Este valor ya está en uso.',
13
+ blank: 'Este campo es obligatorio.'
20
14
  }
21
15
  };
22
16
  exports.default = _default;
@@ -142,9 +142,6 @@ var Form = /*#__PURE__*/function () {
142
142
  }, {
143
143
  name: 'data-hellotext--form-data-value',
144
144
  value: JSON.stringify(this.data)
145
- }, {
146
- name: 'data-action',
147
- value: 'hellotext--otp:verified->hellotext--form#completed'
148
145
  }];
149
146
  }
150
147
  }]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellotext/hellotext",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Hellotext JavaScript Client",
5
5
  "source": "src/index.js",
6
6
  "main": "lib/index.js",
@@ -5,8 +5,6 @@ import { Form } from '../models'
5
5
 
6
6
  import FormsAPI from '../api/forms'
7
7
 
8
- import { OTPBuilder } from '../builders/otp_builder'
9
-
10
8
  export default class extends Controller {
11
9
  static values = {
12
10
  data: Object,
@@ -43,29 +41,34 @@ export default class extends Controller {
43
41
  const response = await FormsAPI.submit(this.form.id, this.formData)
44
42
  this.buttonTarget.disabled = false
45
43
 
44
+ const data = await response.json()
45
+
46
46
  if (response.failed) {
47
- return
47
+ data.errors.forEach(error => {
48
+ const { type, parameter } = error
49
+
50
+ const input = this.inputTargets.find(input => input.name === parameter)
51
+
52
+ input.setCustomValidity(Hellotext.business.locale.errors[type])
53
+ input.reportValidity()
54
+
55
+ input.addEventListener('input', () => {
56
+ input.setCustomValidity('')
57
+ input.reportValidity()
58
+ })
59
+ })
60
+
61
+ return this.showErrorMessages()
48
62
  }
49
63
 
50
64
  this.buttonTarget.style.display = 'none'
51
65
  this.element.querySelectorAll('input').forEach(input => (input.disabled = true))
52
66
 
53
- const submission = await response.json()
54
-
55
- if (submission.identified) {
56
- this.completed()
57
- } else {
58
- Hellotext.setSession(submission.session)
59
- this.revealOTPContainer(submission.id)
67
+ if (!data.identified) {
68
+ Hellotext.setSession(data.session)
60
69
  }
61
- }
62
-
63
- revealOTPContainer(submissionId) {
64
- const paragraph = this.requiredInputs.find(input => input.name === 'email')
65
- ? Hellotext.business.locale.otp.sent_to_email
66
- : Hellotext.business.locale.otp.sent_to_phone
67
70
 
68
- this.element.appendChild(OTPBuilder.build(submissionId, paragraph))
71
+ this.completed()
69
72
  }
70
73
 
71
74
  completed() {
@@ -84,6 +87,7 @@ export default class extends Controller {
84
87
 
85
88
  clearErrorMessages() {
86
89
  this.element.querySelectorAll('input').forEach(input => {
90
+ input.setCustomValidity('')
87
91
  const parent = input.closest('article')
88
92
  parent.querySelector('[data-error-container]').innerText = ''
89
93
  })
package/src/hellotext.js CHANGED
@@ -7,13 +7,12 @@ import { NotInitializedError } from './errors'
7
7
 
8
8
  /**
9
9
  * @typedef {Object} Config
10
- * @property {Boolean} autogenerateSession
10
+ * @property {Boolean} autoGenerateSession
11
11
  * @property {Boolean} autoMountForms
12
12
  */
13
13
 
14
14
  class Hellotext {
15
15
  static #session
16
- static #config
17
16
  static #query
18
17
 
19
18
  static eventEmitter = new Event()
@@ -26,7 +25,8 @@ class Hellotext {
26
25
  * @param { Config } config
27
26
  */
28
27
  static initialize(business, config) {
29
- this.#config = Configuration.assign(config)
28
+ Configuration.assign(config)
29
+
30
30
  this.#query = new Query()
31
31
 
32
32
  this.business = new Business(business)
@@ -36,7 +36,7 @@ class Hellotext {
36
36
 
37
37
  if (this.#query.session) {
38
38
  this.#session = Cookies.set('hello_session', this.#query.session)
39
- } else if (config.autogenerateSession) {
39
+ } else if (Configuration.autoGenerateSession) {
40
40
  this.#mintAnonymousSession().then(response => {
41
41
  this.#session = Cookies.set('hello_session', response.id)
42
42
  })
package/src/index.js CHANGED
@@ -2,11 +2,9 @@ import { Application } from '@hotwired/stimulus'
2
2
  import Hellotext from './hellotext'
3
3
 
4
4
  import FormController from './controllers/form_controller'
5
- import OTPController from './controllers/otp_controller'
6
5
 
7
6
  const application = Application.start()
8
7
  application.register('hellotext--form', FormController)
9
- application.register('hellotext--otp', OTPController)
10
8
 
11
9
  import '../styles/index.css'
12
10
 
package/src/locales/en.js CHANGED
@@ -1,15 +1,9 @@
1
1
  export default {
2
- otp: {
3
- sent_to_email: 'A One-Time Password has been sent to your email address',
4
- sent_to_phone: 'An One-Time Password has been sent to your phone number',
5
- resend_successful: 'The One-Time Password has been resent successfully',
6
- invalid: 'Invalid One-Time Password',
7
- resend: 'Resend verification code',
8
- submit: 'Submit',
9
- throttled: 'You have reached the maximum number of attempts. Please try again in 1 minute.',
10
- placeholder: 'Enter the code here',
11
- },
12
2
  white_label: {
13
3
  powered_by: 'Powered by',
14
4
  },
5
+ errors: {
6
+ parameter_not_unique: 'This value is taken.',
7
+ blank: 'This field is required.'
8
+ }
15
9
  }
package/src/locales/es.js CHANGED
@@ -1,15 +1,9 @@
1
1
  export default {
2
- otp: {
3
- sent_to_email: 'Un código de un solo uso ha sido enviado a tu correo electrónico',
4
- sent_to_phone: 'Un código de un solo uso ha sido enviado a tu número de teléfono',
5
- resend_successful: 'El código de un solo uso ha sido reenviado exitosamente',
6
- invalid: 'Código de un solo uso inválido',
7
- resend: 'Reenviar código de verificación',
8
- submit: 'Enviar',
9
- throttled: 'Has alcanzado el número máximo de intentos. Por favor intenta de nuevo en 1 minuto.',
10
- placeholder: 'Ingresa el código aquí'
11
- },
12
2
  white_label: {
13
3
  powered_by: 'Desarrollado por',
14
4
  },
5
+ errors: {
6
+ parameter_not_unique: 'Este valor ya está en uso.',
7
+ blank: 'Este campo es obligatorio.'
8
+ }
15
9
  }
@@ -118,10 +118,6 @@ class Form {
118
118
  name: 'data-hellotext--form-data-value',
119
119
  value: JSON.stringify(this.data),
120
120
  },
121
- {
122
- name: 'data-action',
123
- value: 'hellotext--otp:verified->hellotext--form#completed',
124
- },
125
121
  ]
126
122
  }
127
123
 
package/styles/index.css CHANGED
@@ -3,6 +3,8 @@ form[data-hello-form] {
3
3
 
4
4
  & article {
5
5
  & [data-error-container] {
6
+ font-size: 0.875rem;
7
+ line-height: 1.25rem;
6
8
  display: none;
7
9
  }
8
10
 
package/alpha.html DELETED
@@ -1,23 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport"
6
- content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
7
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
8
- <title>Document</title>
9
- </head>
10
- <body>
11
-
12
- hello there
13
- <script type="module">
14
- import 'https://unpkg.com/@hellotext/hellotext@latest/dist/hellotext.js';
15
-
16
- Hellotext.initialize('zGrDJ1Lb', {
17
- apiRoot: 'http://api.lvh.me:3000',
18
- })
19
-
20
- // Hellotext.initialize('deadass')
21
- </script>
22
- </body>
23
- </html>
@@ -1,39 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.OTPBuilder = void 0;
7
- var _hellotext = _interopRequireDefault(require("../hellotext"));
8
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
- function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
11
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
12
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
13
- function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
14
- function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; }
15
- var id = 0;
16
- function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; }
17
- var _template = /*#__PURE__*/_classPrivateFieldLooseKey("template");
18
- var OTPBuilder = /*#__PURE__*/function () {
19
- function OTPBuilder() {
20
- _classCallCheck(this, OTPBuilder);
21
- }
22
- _createClass(OTPBuilder, null, [{
23
- key: "build",
24
- value: function build(submissionId, label) {
25
- var element = _classPrivateFieldLooseBase(this, _template)[_template](submissionId, label);
26
- var container = document.createElement('div');
27
- container.innerHTML = element;
28
- return container;
29
- }
30
- }]);
31
- return OTPBuilder;
32
- }();
33
- exports.OTPBuilder = OTPBuilder;
34
- function _template2(submissionId, label) {
35
- return "\n <article \n data-controller=\"hellotext--otp\" \n data-hellotext--otp-submission-id-value=\"".concat(submissionId, "\"\n data-hellotext--form-target=\"otpContainer\"\n data-form-otp\n >\n <header data-otp-header>\n <p>").concat(label, "</p>\n <input \n type=\"text\"\n name=\"otp\"\n data-hellotext--otp-target=\"input\"\n placeholder=\"").concat(_hellotext.default.business.locale.otp.placeholder, "\"\n maxlength=\"6\"\n />\n </header>\n \n <footer data-otp-footer>\n <button type=\"button\" data-hellotext--otp-target=\"submitButton\" data-action=\"hellotext--otp#submit\">\n ").concat(_hellotext.default.business.locale.otp.submit, "\n </button>\n \n <button type=\"button\" data-hellotext--otp-target=\"resendButton\" data-action=\"hellotext--otp#resend\">\n ").concat(_hellotext.default.business.locale.otp.resend, "\n </button>\n </footer>\n </article>\n ");
36
- }
37
- Object.defineProperty(OTPBuilder, _template, {
38
- value: _template2
39
- });
@@ -1,139 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _stimulus = require("@hotwired/stimulus");
8
- var _hellotext = _interopRequireDefault(require("../hellotext"));
9
- var _submissions = _interopRequireDefault(require("../api/submissions"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
- function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
12
- function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
13
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
14
- function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
15
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
16
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
17
- function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
18
- function _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get.bind(); } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); }
19
- function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
20
- function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
21
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
22
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
23
- function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
24
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
25
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
26
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
27
- var _default = /*#__PURE__*/function (_Controller) {
28
- _inherits(_default, _Controller);
29
- var _super = _createSuper(_default);
30
- function _default() {
31
- _classCallCheck(this, _default);
32
- return _super.apply(this, arguments);
33
- }
34
- _createClass(_default, [{
35
- key: "initialize",
36
- value: function initialize() {
37
- _get(_getPrototypeOf(_default.prototype), "initialize", this).call(this);
38
- this.attempts = 0;
39
- this.onInputChange = this.onInputChange.bind(this);
40
- this.throttleInterval = setInterval(() => {
41
- this.attempts = 0;
42
- }, 60000);
43
- }
44
- }, {
45
- key: "connect",
46
- value: function connect() {
47
- this.inputTarget.addEventListener('input', this.onInputChange);
48
- this.inputTarget.focus();
49
- _get(_getPrototypeOf(_default.prototype), "connect", this).call(this);
50
- }
51
- }, {
52
- key: "disconnect",
53
- value: function disconnect() {
54
- clearInterval(this.throttleInterval);
55
- this.inputTarget.removeEventListener('input', this.onInputChange);
56
- _get(_getPrototypeOf(_default.prototype), "disconnect", this).call(this);
57
- }
58
- }, {
59
- key: "resend",
60
- value: function () {
61
- var _resend = _asyncToGenerator(function* () {
62
- if (this.throttled) {
63
- return alert(_hellotext.default.business.locale.otp.throttled);
64
- }
65
- this.resendButtonTarget.disabled = true;
66
- var response = yield _submissions.default.resendOTP(this.submissionIdValue);
67
- if (response.succeeded) {
68
- this.resendButtonTarget.disabled = false;
69
- }
70
- alert(_hellotext.default.business.locale.otp.resend_successful);
71
- this.attempts += 1;
72
- });
73
- function resend() {
74
- return _resend.apply(this, arguments);
75
- }
76
- return resend;
77
- }()
78
- }, {
79
- key: "onInputChange",
80
- value: function onInputChange() {
81
- if (this.inputTarget.value.length !== 6) return;
82
- this.submit();
83
- }
84
- }, {
85
- key: "submit",
86
- value: function () {
87
- var _submit = _asyncToGenerator(function* () {
88
- if (this.inputTarget.value.length !== 6) {
89
- return alert(_hellotext.default.business.locale.otp.invalid);
90
- }
91
- this.disable();
92
- var response = yield _submissions.default.verifyOTP(this.submissionIdValue, this.inputTarget.value);
93
- if (response.succeeded) {
94
- this.dispatch('verified', {
95
- detail: {
96
- submissionId: this.submissionIdValue
97
- }
98
- });
99
- } else {
100
- alert(_hellotext.default.business.locale.otp.invalid);
101
- setTimeout(() => {
102
- this.inputTarget.value = '';
103
- this.inputTarget.focus();
104
- });
105
- }
106
- this.enable();
107
- });
108
- function submit() {
109
- return _submit.apply(this, arguments);
110
- }
111
- return submit;
112
- }() // private
113
- }, {
114
- key: "disable",
115
- value: function disable() {
116
- this.inputTarget.disabled = true;
117
- this.resendButtonTarget.disabled = true;
118
- this.submitButtonTarget.disabled = true;
119
- }
120
- }, {
121
- key: "enable",
122
- value: function enable() {
123
- this.inputTarget.disabled = false;
124
- this.resendButtonTarget.disabled = false;
125
- this.submitButtonTarget.disabled = false;
126
- }
127
- }, {
128
- key: "throttled",
129
- get: function get() {
130
- return this.attempts >= 3;
131
- }
132
- }]);
133
- return _default;
134
- }(_stimulus.Controller);
135
- exports.default = _default;
136
- _default.values = {
137
- submissionId: String
138
- };
139
- _default.targets = ['input', 'submitButton', 'resendButton'];
@@ -1,46 +0,0 @@
1
- import Hellotext from '../hellotext'
2
-
3
- class OTPBuilder {
4
- static build(submissionId, label) {
5
- const element = this.#template(submissionId, label)
6
- const container = document.createElement('div')
7
-
8
- container.innerHTML = element
9
-
10
- return container
11
- }
12
-
13
- static #template(submissionId, label) {
14
- return `
15
- <article
16
- data-controller="hellotext--otp"
17
- data-hellotext--otp-submission-id-value="${submissionId}"
18
- data-hellotext--form-target="otpContainer"
19
- data-form-otp
20
- >
21
- <header data-otp-header>
22
- <p>${label}</p>
23
- <input
24
- type="text"
25
- name="otp"
26
- data-hellotext--otp-target="input"
27
- placeholder="${Hellotext.business.locale.otp.placeholder}"
28
- maxlength="6"
29
- />
30
- </header>
31
-
32
- <footer data-otp-footer>
33
- <button type="button" data-hellotext--otp-target="submitButton" data-action="hellotext--otp#submit">
34
- ${Hellotext.business.locale.otp.submit}
35
- </button>
36
-
37
- <button type="button" data-hellotext--otp-target="resendButton" data-action="hellotext--otp#resend">
38
- ${Hellotext.business.locale.otp.resend}
39
- </button>
40
- </footer>
41
- </article>
42
- `
43
- }
44
- }
45
-
46
- export { OTPBuilder }