@subiz/widget-v4 4.1.218 → 4.1.222

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 (128) hide show
  1. package/assets/img/bar_ho_tro.svg +3 -0
  2. package/{dist/assets/img/bubble_default.6f6eec8.svg → assets/img/bubble_11.svg} +0 -1
  3. package/assets/less/form-page.less +58 -0
  4. package/assets/less/form.less +279 -3
  5. package/assets/less/widget.less +6 -0
  6. package/compiled_src/chatbox/ChatButton.js +22 -3
  7. package/compiled_src/chatbox/Widget.js +13 -18
  8. package/compiled_src/form/Form.js +270 -71
  9. package/compiled_src/form/FormPage.js +17 -4
  10. package/compiled_src/form/form-fields.js +244 -0
  11. package/compiled_src/form/index.js +2 -0
  12. package/compiled_src/form/rating-stars.js +48 -88
  13. package/compiled_src/plugin.js +10 -0
  14. package/compiled_src/store/api.js +5 -7
  15. package/compiled_src/store/api_fake.js +3 -1
  16. package/compiled_src/store/localize.js +33 -0
  17. package/compiled_src/store/store.js +57 -1
  18. package/compiled_src/store/widget-settings.js +67 -0
  19. package/compiled_src/util/common.js +1 -1
  20. package/package.json +3 -3
  21. package/src/chatbox/ChatButton.js +25 -4
  22. package/src/chatbox/Widget.js +21 -21
  23. package/src/form/Form.js +335 -97
  24. package/src/form/FormPage.js +21 -8
  25. package/src/form/form-fields.js +224 -0
  26. package/src/form/index.js +6 -1
  27. package/src/form/rating-stars.js +48 -64
  28. package/src/plugin.js +10 -0
  29. package/src/store/api.js +9 -7
  30. package/src/store/api_fake.js +3 -1
  31. package/src/store/localize.js +30 -0
  32. package/src/store/store.js +64 -1
  33. package/src/store/widget-settings.js +46 -0
  34. package/src/util/common.js +1 -1
  35. package/test.cjs +3 -0
  36. package/webpack.dev.js +2 -0
  37. package/dist/127.js +0 -273
  38. package/dist/132.js +0 -2817
  39. package/dist/185.js +0 -1917
  40. package/dist/1a12ed33347.127.js +0 -1
  41. package/dist/1a12ed33347.132.js +0 -1
  42. package/dist/1a12ed33347.185.js +0 -1
  43. package/dist/1a12ed33347.27.js +0 -1
  44. package/dist/1a12ed33347.278.js +0 -1
  45. package/dist/1a12ed33347.339.js +0 -1
  46. package/dist/1a12ed33347.459.js +0 -1
  47. package/dist/1a12ed33347.490.js +0 -1
  48. package/dist/1a12ed33347.app.js +0 -1
  49. package/dist/1a12ed33347.chat.html +0 -1
  50. package/dist/1a12ed33347.chat.js +0 -1
  51. package/dist/1a12ed33347.form.html +0 -1
  52. package/dist/1a12ed33347.form.js +0 -1
  53. package/dist/1a12ed33347.index.html +0 -72
  54. package/dist/1a12ed33347.library.html +0 -72
  55. package/dist/1a12ed33347.library.js +0 -1
  56. package/dist/1a12ed33347.preview.html +0 -759
  57. package/dist/1a12ed33347.preview.js +0 -1
  58. package/dist/1a12ed33347.webview.js +0 -1
  59. package/dist/27.js +0 -37
  60. package/dist/459.js +0 -37
  61. package/dist/490.js +0 -305
  62. package/dist/HASH +0 -1
  63. package/dist/assets/img/Facebook.64607ec.png +0 -0
  64. package/dist/assets/img/Zalo.6845707.png +0 -0
  65. package/dist/assets/img/award1a.1a58e10.png +0 -0
  66. package/dist/assets/img/award3a.3b74423.png +0 -0
  67. package/dist/assets/img/award4a.ed6ccd4.png +0 -0
  68. package/dist/assets/img/award5.39eb7ae.png +0 -0
  69. package/dist/assets/img/caret.998eb8f.svg +0 -1
  70. package/dist/assets/img/convos_empty.2353007.svg +0 -72
  71. package/dist/assets/img/default.06e6ee0.jpg +0 -0
  72. package/dist/assets/img/default_avatar.e449b04.png +0 -0
  73. package/dist/assets/img/default_logo.dd13a2b.svg +0 -5
  74. package/dist/assets/img/done_gray.d7e8203.svg +0 -4
  75. package/dist/assets/img/done_green.b817fd4.svg +0 -4
  76. package/dist/assets/img/dot_chat.335fd8a.svg +0 -3
  77. package/dist/assets/img/emoji/messenger/sub_23.529_58.824.d5faf14.png +0 -0
  78. package/dist/assets/img/emoji/messenger/sub_23.529_60.784.1420241.png +0 -0
  79. package/dist/assets/img/emoji/messenger/sub_25.490_0.000.1e6b2c0.png +0 -0
  80. package/dist/assets/img/emoji/messenger/sub_25.490_45.098.3dfbc08.png +0 -0
  81. package/dist/assets/img/emoji/messenger/sub_25.490_5.882.4b49e94.png +0 -0
  82. package/dist/assets/img/emoji/messenger/sub_27.451_72.549.7114f58.png +0 -0
  83. package/dist/assets/img/emoji/messenger/sub_27.451_84.314.231e2b7.png +0 -0
  84. package/dist/assets/img/emoji/messenger/sub_27.451_96.078.ddbb008.png +0 -0
  85. package/dist/assets/img/emoji/messenger/sub_29.412_5.882.61f3359.png +0 -0
  86. package/dist/assets/img/emoji/messenger/sub_58.824_100.000.6df72bc.png +0 -0
  87. package/dist/assets/img/emoji/messenger/sub_58.824_45.098.3d7a7ad.png +0 -0
  88. package/dist/assets/img/emoji/messenger/sub_58.824_47.059.0f4d6e2.png +0 -0
  89. package/dist/assets/img/emoji/messenger/sub_58.824_54.902.65724c1.png +0 -0
  90. package/dist/assets/img/emoji/messenger/sub_58.824_64.706.9da3cba.png +0 -0
  91. package/dist/assets/img/emoji/messenger/sub_58.824_72.549.edca5cf.png +0 -0
  92. package/dist/assets/img/emoji/messenger/sub_58.824_78.431.f910f2a.png +0 -0
  93. package/dist/assets/img/emoji/messenger/sub_58.824_88.235.def4e71.png +0 -0
  94. package/dist/assets/img/emoji/messenger/sub_60.784_11.765.49c03d0.png +0 -0
  95. package/dist/assets/img/emoji/messenger/sub_60.784_27.451.46b54e5.png +0 -0
  96. package/dist/assets/img/emoji/messenger/sub_60.784_29.412.e36d284.png +0 -0
  97. package/dist/assets/img/emoji/messenger/sub_60.784_3.922.bb191b0.png +0 -0
  98. package/dist/assets/img/emoji/messenger/sub_60.784_35.294.af7b927.png +0 -0
  99. package/dist/assets/img/emoji/messenger/sub_60.784_7.843.98f2a99.png +0 -0
  100. package/dist/assets/img/empty.29bed2d.svg +0 -23
  101. package/dist/assets/img/empty_1.0b98af0.svg +0 -11
  102. package/dist/assets/img/examplte_logo.f86535f.svg +0 -1
  103. package/dist/assets/img/external-link.90577cc.svg +0 -1
  104. package/dist/assets/img/fb_inverse_circle.36c2cfc.png +0 -0
  105. package/dist/assets/img/ghn.070f8e3.svg +0 -17
  106. package/dist/assets/img/ghtk.326eac1.svg +0 -18
  107. package/dist/assets/img/image_default.be0698b.png +0 -0
  108. package/dist/assets/img/info.ebce7ea.svg +0 -1
  109. package/dist/assets/img/loader.37000a7.svg +0 -1
  110. package/dist/assets/img/loading_static.a27f0ac.svg +0 -10
  111. package/dist/assets/img/main-service1.d536cc2.png +0 -0
  112. package/dist/assets/img/main-service2.9b99549.png +0 -0
  113. package/dist/assets/img/not_found_search.2ddb8d1.png +0 -0
  114. package/dist/assets/img/package.8d37d0f.svg +0 -5
  115. package/dist/assets/img/package_fade.763c001.svg +0 -1
  116. package/dist/assets/img/rating--average.1ea492c.svg +0 -12
  117. package/dist/assets/img/rating--great.e3d712e.svg +0 -16
  118. package/dist/assets/img/rating--poor.2938a25.svg +0 -12
  119. package/dist/assets/img/search.f9705ff.svg +0 -1
  120. package/dist/assets/img/send.6db52a9.svg +0 -3
  121. package/dist/assets/img/shop.f7dc7d8.svg +0 -1
  122. package/dist/assets/img/shop_faded.df7845a.svg +0 -1
  123. package/dist/assets/img/stars_v2.79cf728.png +0 -0
  124. package/dist/assets/img/subiz-mono.8fbc067.svg +0 -3
  125. package/dist/assets/img/x.26fdfa3.svg +0 -5
  126. package/dist/malicious-app.js +0 -17
  127. package/dist/screenshoot.html +0 -7
  128. package/dist/screenshoot.js +0 -14454
@@ -9,6 +9,7 @@ var _preact = require("preact");
9
9
  var _index = _interopRequireDefault(require("../util/index.js"));
10
10
  var _block = _interopRequireDefault(require("../chatbox/block.js"));
11
11
  var _ratingStars = _interopRequireDefault(require("./rating-stars.js"));
12
+ var _formFields = require("./form-fields.js");
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
14
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
14
15
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
@@ -18,7 +19,19 @@ class Form2 extends _common.Com {
18
19
  super(props);
19
20
  _defineProperty(this, "state", {
20
21
  errorFields: {},
21
- submiting: false
22
+ submiting: false,
23
+ otherSelected: {},
24
+ otherText: {}
25
+ });
26
+ _defineProperty(this, "getRef", name => {
27
+ if (!this[name]) this[name] = (0, _preact.createRef)();
28
+ return this[name];
29
+ });
30
+ _defineProperty(this, "tr", key => (0, _formFields.translate)(this.props.t, key));
31
+ _defineProperty(this, "getValue", (key, def) => {
32
+ let val = _index.default.find(_index.default.get(this.props.submission, 'values'), f => f.key === key) || {};
33
+ val = val.value || def || '""';
34
+ return _index.default.parseJSON(val);
22
35
  });
23
36
  _defineProperty(this, "renderFormComponent", (com, idx) => {
24
37
  if (com.type === 'input') return this.renderField(com, idx);
@@ -41,44 +54,92 @@ class Form2 extends _common.Com {
41
54
  disabled: this.props.submiting
42
55
  }, com.label)));
43
56
  });
57
+ _defineProperty(this, "renderSubmittedValue", com => {
58
+ let empty = (0, _preact.h)("span", {
59
+ class: "text-muted text-italic"
60
+ }, this.props.t('no_info_input'));
61
+ let val = this.getValue(com.key);
62
+ if (com.input_type === 'rating') {
63
+ let cfg = (0, _formFields.getRatingConfig)(com);
64
+ let idx = _index.default.size(cfg.levels) ? cfg.levels.findIndex(l => (0, _formFields.sameValue)(val, l.value)) : -1;
65
+ if (idx < 0) return empty;
66
+ if (cfg.kind === 'face') return (0, _preact.h)(_formFields.RatingFaces, {
67
+ readonly: true,
68
+ levels: [cfg.levels[idx]],
69
+ value: val
70
+ });
71
+ return (0, _preact.h)("div", {
72
+ class: "form-submitted-rating"
73
+ }, (0, _preact.h)(_ratingStars.default, {
74
+ readonly: true,
75
+ count: cfg.levels.length,
76
+ value: idx + 1
77
+ }), (0, _preact.h)("span", {
78
+ class: "text-muted"
79
+ }, idx + 1, "/", cfg.levels.length));
80
+ }
81
+ if (com.input_type === 'linear_scale') {
82
+ if ((0, _formFields.isEmptyValue)(val)) return empty;
83
+ let {
84
+ min,
85
+ max
86
+ } = (0, _formFields.getScaleRange)(com);
87
+ let text = `${val}/${max}`;
88
+ if ((0, _formFields.sameValue)(val, min) && com.scale_min_label) text += ` · ${com.scale_min_label}`;
89
+ if ((0, _formFields.sameValue)(val, max) && com.scale_max_label) text += ` · ${com.scale_max_label}`;
90
+ return (0, _preact.h)("div", null, text);
91
+ }
92
+ if (['radio', 'checkbox', 'dropdown', 'select'].includes(com.input_type)) {
93
+ let vals = Array.isArray(val) ? val : (0, _formFields.isEmptyValue)(val) ? [] : [val];
94
+ let labels = _index.default.map(vals, v => (0, _formFields.optionLabel)(com, v));
95
+ if (labels.length === 0) return empty;
96
+ if (com.input_type === 'checkbox' && (0, _formFields.isChips)(com)) {
97
+ return (0, _preact.h)("div", {
98
+ class: "form-chips readonly"
99
+ }, _index.default.map(labels, label => (0, _preact.h)("span", {
100
+ class: "form-chip selected"
101
+ }, label)));
102
+ }
103
+ return (0, _preact.h)("div", null, labels.join(', '));
104
+ }
105
+ if (Array.isArray(val)) val = val.join(', ');
106
+ return (0, _preact.h)("div", null, val || empty);
107
+ });
44
108
  _defineProperty(this, "renderField", (com, idx) => {
45
109
  let errorMsg = this.state.errorFields[com.key];
46
110
  if (this.props.isSubmited) {
47
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
48
- val = val.value || '""';
49
- val = _index.default.parseJSON(val);
50
- if (Array.isArray(val)) val = val.join(', ');
51
111
  return (0, _preact.h)("div", {
52
112
  class: "form-component submitted",
53
113
  key: com.key
54
114
  }, (0, _preact.h)("label", {
55
115
  class: "label"
56
- }, com.label), (0, _preact.h)("div", null, val || (0, _preact.h)("span", {
57
- class: "text-muted text-italic"
58
- }, this.props.t('no_info_input'))));
116
+ }, com.label), this.renderSubmittedValue(com));
59
117
  }
118
+ let desc = (0, _formFields.getDescription)(com);
119
+ let cls = 'form-component';
120
+ if (desc) cls += ' has-description';
60
121
  return (0, _preact.h)("div", {
61
- class: "form-component",
122
+ class: cls,
62
123
  key: com.key
63
124
  }, (0, _preact.h)("label", {
64
125
  class: "label"
65
126
  }, com.label, " ", com.is_required && (0, _preact.h)("span", {
66
127
  class: "red"
67
- }, "*")), com.input_type === 'text' && this.renderFieldTextInput(com, idx), com.input_type === 'textarea' && this.renderFieldTextareaInput(com, idx), com.input_type === 'date' && this.renderFieldDateInput(com, idx), com.input_type === 'radio' && this.renderFieldRadioInput(com, idx), com.input_type === 'checkbox' && this.renderFieldCheckboxInput(com, idx), (com.input_type === 'dropdown' || com.input_type === 'select') && this.renderFieldDropdownInput(com, idx), com.input_type === 'rating' && this.renderFieldRatingInput(com, idx), errorMsg && (0, _preact.h)("div", {
128
+ }, "*")), desc && (0, _preact.h)("div", {
129
+ class: "form-field-description"
130
+ }, desc), com.input_type === 'text' && this.renderFieldTextInput(com, idx), com.input_type === 'textarea' && this.renderFieldTextareaInput(com, idx), com.input_type === 'date' && this.renderFieldDateInput(com, idx), com.input_type === 'radio' && this.renderFieldRadioInput(com, idx), com.input_type === 'checkbox' && ((0, _formFields.isChips)(com) ? this.renderFieldChipsInput(com, idx) : this.renderFieldCheckboxInput(com, idx)), (com.input_type === 'dropdown' || com.input_type === 'select') && this.renderFieldDropdownInput(com, idx), com.input_type === 'rating' && this.renderFieldRatingInput(com, idx), com.input_type === 'linear_scale' && this.renderFieldLinearScaleInput(com, idx), errorMsg && (0, _preact.h)("div", {
68
131
  class: "form-control--valid-input--error"
69
132
  }, errorMsg));
70
133
  });
71
134
  _defineProperty(this, "renderFieldTextInput", (com, idx) => {
72
135
  let cls = 'form-control';
73
136
  if (this.state.errorFields[com.key]) cls = 'form-control input--error';
74
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
75
- val = val.value || '""';
76
- val = _index.default.parseJSON(val);
137
+ let val = this.getValue(com.key);
77
138
  return (0, _preact.h)("input", {
78
- ref: this[`${com.key}_input`],
139
+ ref: this.getRef(`${com.key}_input`),
79
140
  type: "text",
80
141
  class: cls,
81
- placeholder: com.placeholder,
142
+ placeholder: (0, _formFields.getPlaceholder)(com),
82
143
  value: val,
83
144
  onInput: e => {
84
145
  this.onChangeValue(com.key, e.target.value);
@@ -87,13 +148,11 @@ class Form2 extends _common.Com {
87
148
  });
88
149
  });
89
150
  _defineProperty(this, "renderFieldDateInput", (com, idx) => {
90
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
91
- val = val.value || '""';
92
- val = _index.default.parseJSON(val);
151
+ let val = this.getValue(com.key);
93
152
  let cls = 'form-control';
94
153
  if (this.state.errorFields[com.key]) cls = 'form-control input--error';
95
154
  return (0, _preact.h)("input", {
96
- ref: this[`${com.key}_input`],
155
+ ref: this.getRef(`${com.key}_input`),
97
156
  class: cls,
98
157
  type: "date",
99
158
  value: val,
@@ -103,13 +162,26 @@ class Form2 extends _common.Com {
103
162
  }
104
163
  });
105
164
  });
165
+ _defineProperty(this, "renderOtherTextInput", com => {
166
+ if (!com.allow_other_option || !this.state.otherSelected[com.key]) return null;
167
+ let cls = 'form-control form-other-input';
168
+ if (this.state.errorFields[com.key]) cls += ' input--error';
169
+ return (0, _preact.h)("input", {
170
+ ref: this.getRef(`${com.key}_other_input`),
171
+ type: "text",
172
+ class: cls,
173
+ placeholder: this.tr('form_other_option_placeholder'),
174
+ value: this.state.otherText[com.key] || '',
175
+ onInput: e => this.setOtherText(com, e.target.value)
176
+ });
177
+ });
106
178
  _defineProperty(this, "renderFieldRadioInput", (com, idx) => {
107
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
108
- val = val.value || '""';
109
- val = _index.default.parseJSON(val);
179
+ let val = this.getValue(com.key);
180
+ let otherOn = !!this.state.otherSelected[com.key];
110
181
  let wrappercls = 'form-radios-wrapper';
111
- if (_index.default.size(com.input_options) >= 3 && this.props.mode !== 'attachment') wrappercls += ' horizontal';
112
- return (0, _preact.h)("div", {
182
+ let count = _index.default.size(com.input_options) + (com.allow_other_option ? 1 : 0);
183
+ if (count >= 3 && this.props.mode !== 'attachment') wrappercls += ' horizontal';
184
+ return (0, _preact.h)(_preact.Fragment, null, (0, _preact.h)("div", {
113
185
  class: wrappercls
114
186
  }, _index.default.map(com.input_options, (option, oidx) => {
115
187
  let id = com.key + '_' + oidx;
@@ -119,7 +191,7 @@ class Form2 extends _common.Com {
119
191
  type: "radio",
120
192
  name: com.key,
121
193
  id: id,
122
- checked: option.value === val,
194
+ checked: !otherOn && option.value === val,
123
195
  onChange: () => this.toggleRadioField(com.key, option.value)
124
196
  }), (0, _preact.h)("label", {
125
197
  class: "radio--label",
@@ -127,15 +199,29 @@ class Form2 extends _common.Com {
127
199
  }, option.label), (0, _preact.h)("div", {
128
200
  class: "radio--check"
129
201
  }));
130
- }));
202
+ }), com.allow_other_option && (0, _preact.h)("div", {
203
+ class: "radio"
204
+ }, (0, _preact.h)("input", {
205
+ type: "radio",
206
+ name: com.key,
207
+ id: com.key + '_other',
208
+ checked: otherOn,
209
+ onChange: () => this.setOtherSelected(com, true)
210
+ }), (0, _preact.h)("label", {
211
+ class: "radio--label",
212
+ for: com.key + '_other'
213
+ }, this.tr('form_other_option')), (0, _preact.h)("div", {
214
+ class: "radio--check"
215
+ }))), this.renderOtherTextInput(com));
131
216
  });
132
217
  _defineProperty(this, "renderFieldCheckboxInput", (com, idx) => {
133
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
134
- val = val.value || '[]';
135
- val = _index.default.parseJSON(val);
218
+ let val = this.getValue(com.key, '[]');
219
+ if (!Array.isArray(val)) val = [];
220
+ let otherOn = !!this.state.otherSelected[com.key];
136
221
  let wrappercls = 'form-checkboxes-wrapper';
137
- if (_index.default.size(com.input_options) >= 3 && this.props.mode !== 'attachment') wrappercls += ' horizontal';
138
- return (0, _preact.h)("div", {
222
+ let count = _index.default.size(com.input_options) + (com.allow_other_option ? 1 : 0);
223
+ if (count >= 3 && this.props.mode !== 'attachment') wrappercls += ' horizontal';
224
+ return (0, _preact.h)(_preact.Fragment, null, (0, _preact.h)("div", {
139
225
  class: wrappercls
140
226
  }, _index.default.map(com.input_options, (option, oidx) => {
141
227
  let id = com.key + '_' + oidx;
@@ -153,20 +239,59 @@ class Form2 extends _common.Com {
153
239
  }, option.label), (0, _preact.h)("div", {
154
240
  class: "checkbox--check"
155
241
  }));
156
- }));
242
+ }), com.allow_other_option && (0, _preact.h)("div", {
243
+ class: "checkbox"
244
+ }, (0, _preact.h)("input", {
245
+ type: "checkbox",
246
+ name: com.key,
247
+ id: com.key + '_other',
248
+ checked: otherOn,
249
+ onChange: () => this.setOtherSelected(com, !otherOn)
250
+ }), (0, _preact.h)("label", {
251
+ class: "checkbox--label",
252
+ for: com.key + '_other'
253
+ }, this.tr('form_other_option')), (0, _preact.h)("div", {
254
+ class: "checkbox--check"
255
+ }))), this.renderOtherTextInput(com));
256
+ });
257
+ _defineProperty(this, "renderFieldChipsInput", (com, idx) => {
258
+ let val = this.getValue(com.key, '[]');
259
+ if (!Array.isArray(val)) val = [];
260
+ let otherOn = !!this.state.otherSelected[com.key];
261
+ return (0, _preact.h)(_preact.Fragment, null, (0, _preact.h)("div", {
262
+ class: "form-chips",
263
+ role: "group"
264
+ }, _index.default.map(com.input_options, option => {
265
+ let selected = val.includes(option.value);
266
+ return (0, _preact.h)("button", {
267
+ type: "button",
268
+ class: 'form-chip' + (selected ? ' selected' : ''),
269
+ "aria-pressed": selected ? 'true' : 'false',
270
+ onClick: () => this.toggleCheckboxField(com.key, option.value)
271
+ }, option.label || option.value);
272
+ }), com.allow_other_option && (0, _preact.h)("button", {
273
+ type: "button",
274
+ class: 'form-chip form-chip-other' + (otherOn ? ' selected' : ''),
275
+ "aria-pressed": otherOn ? 'true' : 'false',
276
+ onClick: () => this.setOtherSelected(com, !otherOn)
277
+ }, this.tr('form_other_option'))), this.renderOtherTextInput(com));
157
278
  });
158
279
  _defineProperty(this, "renderFieldDropdownInput", (com, idx) => {
159
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
160
- val = val.value || '""';
161
- val = _index.default.parseJSON(val);
280
+ let val = this.getValue(com.key);
281
+ let otherOn = !!this.state.otherSelected[com.key];
162
282
  let cls = 'form-control';
163
- if (this.state.errorFields[com.key]) cls += ' input--error';
164
- if (!val) cls += ' form-control--empty';
165
- return (0, _preact.h)("select", {
283
+ if (this.state.errorFields[com.key] && !otherOn) cls += ' input--error';
284
+ if (!val && !otherOn) cls += ' form-control--empty';
285
+ return (0, _preact.h)(_preact.Fragment, null, (0, _preact.h)("select", {
166
286
  class: cls,
167
- ref: this[`${com.key}_input`],
287
+ ref: this.getRef(`${com.key}_input`),
288
+ value: otherOn ? _formFields.OTHER_OPTION_VALUE : val || '',
168
289
  onChange: e => {
169
- this.onChangeValue(com.key, e.target.value);
290
+ if (e.target.value === _formFields.OTHER_OPTION_VALUE) {
291
+ this.setOtherSelected(com, true);
292
+ return;
293
+ }
294
+ if (otherOn) this.setOtherSelected(com, false, e.target.value);else this.onChangeValue(com.key, e.target.value);
170
295
  this.clearError(com.key);
171
296
  }
172
297
  }, (0, _preact.h)("option", {
@@ -175,26 +300,52 @@ class Form2 extends _common.Com {
175
300
  return (0, _preact.h)("option", {
176
301
  value: option.value
177
302
  }, option.label);
178
- }));
303
+ }), com.allow_other_option && (0, _preact.h)("option", {
304
+ value: _formFields.OTHER_OPTION_VALUE
305
+ }, this.tr('form_other_option'))), this.renderOtherTextInput(com));
179
306
  });
180
307
  _defineProperty(this, "renderFieldTextareaInput", (com, idx) => {
181
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
182
- val = val.value || '""';
183
- val = _index.default.parseJSON(val);
308
+ let cls = 'form-control';
309
+ if (this.state.errorFields[com.key]) cls += ' input--error';
184
310
  return (0, _preact.h)("textarea", {
185
311
  onInput: e => {
186
312
  this.onChangeValue(com.key, e.target.value);
187
313
  this.clearError(com.key);
188
314
  },
189
- ref: this[`${com.key}_input`],
315
+ ref: this.getRef(`${com.key}_input`),
190
316
  rows: "3",
191
- class: "form-control",
192
- placeholder: com.placeholder
317
+ class: cls,
318
+ placeholder: (0, _formFields.getPlaceholder)(com)
193
319
  });
194
320
  });
195
321
  _defineProperty(this, "renderFieldRatingInput", (com, idx) => {
322
+ let cfg = (0, _formFields.getRatingConfig)(com);
323
+ let val = this.getValue(com.key);
324
+ let onChange = v => {
325
+ this.onChangeValue(com.key, v);
326
+ this.clearError(com.key);
327
+ };
328
+ if (cfg.kind === 'face') return (0, _preact.h)(_formFields.RatingFaces, {
329
+ levels: cfg.levels,
330
+ value: val,
331
+ onChange: onChange
332
+ });
333
+ let selectedIdx = cfg.levels.findIndex(l => (0, _formFields.sameValue)(val, l.value));
196
334
  return (0, _preact.h)(_ratingStars.default, {
197
- onChange: v => this.onChangeValue(com.key, v)
335
+ count: cfg.levels.length,
336
+ value: selectedIdx + 1,
337
+ onChange: n => onChange(n > 0 ? (0, _formFields.toStoredValue)(cfg.levels[n - 1].value) : '')
338
+ });
339
+ });
340
+ _defineProperty(this, "renderFieldLinearScaleInput", (com, idx) => {
341
+ return (0, _preact.h)(_formFields.LinearScale, {
342
+ com: com,
343
+ numberedLabels: this.props.mode === 'attachment',
344
+ value: this.getValue(com.key),
345
+ onChange: v => {
346
+ this.onChangeValue(com.key, v);
347
+ this.clearError(com.key);
348
+ }
198
349
  });
199
350
  });
200
351
  _defineProperty(this, "onSubmit", e => {
@@ -209,20 +360,18 @@ class Form2 extends _common.Com {
209
360
  let components = _index.default.get(this.props.formSetting, 'components') || [];
210
361
  _index.default.each(components, com => {
211
362
  if (com.type === 'input') {
212
- let val = _index.default.find(this.props.submission.values, f => f.key === com.key) || {};
213
- val = val.value || '""';
214
- val = _index.default.parseJSON(val);
363
+ let val = this.getValue(com.key);
215
364
  if (com.is_required) {
216
- let isEmpty = false;
217
- if (typeof val === 'string' && !val.trim()) isEmpty = true;
218
- if (Array.isArray(val) && val.length === 0) isEmpty = true;
365
+ let isEmpty = (0, _formFields.isEmptyValue)(val);
366
+ if (com.input_type === 'rating' && val === 0) isEmpty = true;
219
367
  if (isEmpty) {
220
368
  result = false;
221
369
  errors[com.key] = this.props.t('cannot_be_empty');
222
- ref = `${com.key}_input`;
370
+ if (!ref) ref = this.state.otherSelected[com.key] ? `${com.key}_other_input` : `${com.key}_input`;
223
371
  }
224
372
  }
225
- if (com.validation && !Array.isArray(val)) {
373
+ let isChoice = ['rating', 'linear_scale', 'radio', 'checkbox', 'dropdown', 'select'].includes(com.input_type);
374
+ if (com.validation && !Array.isArray(val) && !isChoice) {
226
375
  let isInvalid = false;
227
376
  let validationText = '';
228
377
  if (com.validation === 'email' && !_index.default.isEmail(val)) {
@@ -244,7 +393,7 @@ class Form2 extends _common.Com {
244
393
  if (isInvalid) {
245
394
  result = false;
246
395
  errors[com.key] = this.props.t('format_is_invalid') + ' ' + validationText;
247
- ref = `${com.key}_input`;
396
+ if (!ref) ref = `${com.key}_input`;
248
397
  }
249
398
  }
250
399
  }
@@ -257,6 +406,50 @@ class Form2 extends _common.Com {
257
406
  });
258
407
  return result;
259
408
  });
409
+ _defineProperty(this, "getComponent", key => _index.default.find(_index.default.get(this.props.formSetting, 'components') || [], c => c.key === key));
410
+ _defineProperty(this, "commitCheckboxValue", (com, optionValues, otherOn, otherText) => {
411
+ let values = _index.default.filter(optionValues, v => _index.default.find(com.input_options, o => o.value === v));
412
+ let text = (otherText || '').trim();
413
+ if (otherOn && text) values.push(text);
414
+ this.onChangeValue(com.key, values);
415
+ });
416
+ _defineProperty(this, "setOtherSelected", (com, on, nextValue) => {
417
+ let key = com.key;
418
+ let otherSelected = {
419
+ ...this.state.otherSelected,
420
+ [key]: on
421
+ };
422
+ let text = this.state.otherText[key] || '';
423
+ this.clearError(key);
424
+ this.setState({
425
+ otherSelected
426
+ }, () => {
427
+ let $input = this.getRef(`${key}_other_input`).current;
428
+ if (on && $input) {
429
+ $input.focus();
430
+ }
431
+ });
432
+ if (com.input_type === 'checkbox') {
433
+ this.commitCheckboxValue(com, this.getValue(key, '[]') || [], on, text);
434
+ return;
435
+ }
436
+ this.onChangeValue(key, on ? text.trim() : nextValue || '');
437
+ });
438
+ _defineProperty(this, "setOtherText", (com, text) => {
439
+ let key = com.key;
440
+ this.setState({
441
+ otherText: {
442
+ ...this.state.otherText,
443
+ [key]: text
444
+ }
445
+ });
446
+ this.clearError(key);
447
+ if (com.input_type === 'checkbox') {
448
+ this.commitCheckboxValue(com, this.getValue(key, '[]') || [], true, text);
449
+ return;
450
+ }
451
+ this.onChangeValue(key, text.trim());
452
+ });
260
453
  _defineProperty(this, "onChangeValue", (key, v) => {
261
454
  let formValues = _index.default.get(this.props.submission, 'values') || [];
262
455
  let f = _index.default.find(formValues, field => field.key === key);
@@ -283,9 +476,11 @@ class Form2 extends _common.Com {
283
476
  if (this.props.mode === 'attachment') {
284
477
  if (title.trim() || desc.trim()) {
285
478
  return (0, _preact.h)("div", {
286
- class: "form-component form-component-block"
287
- }, title && (0, _preact.h)("div", null, title), desc && (0, _preact.h)("div", {
288
- class: "text-sm text-muted"
479
+ class: "form-component form-component-block form-attachment-header"
480
+ }, title && (0, _preact.h)("div", {
481
+ class: "form-attachment-title"
482
+ }, title), desc && (0, _preact.h)("div", {
483
+ class: "form-attachment-desc text-sm text-muted"
289
484
  }, desc));
290
485
  }
291
486
  }
@@ -314,33 +509,37 @@ class Form2 extends _common.Com {
314
509
  }
315
510
  return (0, _preact.h)(_preact.Fragment, null, $logo, $header);
316
511
  });
317
- let _components = _index.default.get(this.props.formSetting, 'components') || [];
318
- _index.default.each(_components, com => {
319
- if (com.type === 'input' && com.input_type !== 'checkbox' && com.input_type !== 'radio') {
320
- this[`${com.key}_input`] = (0, _preact.createRef)();
321
- }
322
- });
323
512
  }
324
513
  toggleRadioField(key, v) {
325
514
  this.clearError(key);
515
+ if (this.state.otherSelected[key]) {
516
+ this.setState({
517
+ otherSelected: {
518
+ ...this.state.otherSelected,
519
+ [key]: false
520
+ }
521
+ });
522
+ }
326
523
  this.onChangeValue(key, v);
327
524
  }
328
525
  toggleCheckboxField(key, v) {
329
- let currentValues = _index.default.find(this.props.submission.values, f => f.key === key) || {};
330
- currentValues = currentValues.value || '[]';
331
- currentValues = _index.default.parseJSON(currentValues);
526
+ let currentValues = this.getValue(key, '[]');
527
+ if (!Array.isArray(currentValues)) currentValues = [];
332
528
  if (currentValues.includes(v)) {
333
529
  currentValues = currentValues.filter(s => s !== v);
334
530
  } else {
335
531
  currentValues.push(v);
336
532
  }
337
533
  this.clearError(key);
534
+ let com = this.getComponent(key);
535
+ if (com && com.allow_other_option) {
536
+ this.commitCheckboxValue(com, currentValues, this.state.otherSelected[key], this.state.otherText[key]);
537
+ return;
538
+ }
338
539
  this.onChangeValue(key, currentValues);
339
540
  }
340
541
  render() {
341
542
  let components = _index.default.get(this.props.formSetting, 'components') || [];
342
- let title = _index.default.get(this.props.formSetting, 'title') || '';
343
- let desc = _index.default.get(this.props.formSetting, 'description') || '';
344
543
  let cls = 'form-wrapper form';
345
544
  if (this.props.mode === 'attachment') cls += ' form-wrapper-attachment';
346
545
  return (0, _preact.h)("div", {
@@ -56,11 +56,11 @@ class FormPage extends _common.Com {
56
56
  let descFont = _index.default.get(formSetting, 'text_style.font_family');
57
57
  let inputLabelFont = _index.default.get(formSetting, 'input_style.font_family');
58
58
  setting.form_background_color = formSetting.background_color;
59
- setting.form_header_font_size = _index.default.get(formSetting, 'header_style.font_size') || '20';
59
+ setting.form_header_font_size = _index.default.get(formSetting, 'header_style.font_size') || '28';
60
60
  setting.form_header_font_family = headerFont;
61
61
  setting.form_desc_font_size = _index.default.get(formSetting, 'text_style.font_size') || '16';
62
62
  setting.form_desc_font_family = descFont;
63
- setting.form_input_label_font_size = _index.default.get(formSetting, 'input_style.font_size') || '14';
63
+ setting.form_input_label_font_size = _index.default.get(formSetting, 'input_style.font_size') || '16';
64
64
  setting.form_input_label_font_family = inputLabelFont;
65
65
  let outcss = _index.default.replaceCssVariable(css, setting);
66
66
  let fonts = [];
@@ -94,7 +94,12 @@ class FormPage extends _common.Com {
94
94
  this.setState({
95
95
  loading: true
96
96
  });
97
- let res = await this.props.store.checkFormToken(this.props.store.matchAccount().id, this.props.token);
97
+ let res;
98
+ if (this.props.token) {
99
+ res = await this.props.store.checkFormToken(this.props.store.matchAccount().id, this.props.token);
100
+ } else {
101
+ res = await this.props.store.getPublicForm(this.props.formId);
102
+ }
98
103
  if (res.error) {
99
104
  this.setState({
100
105
  loading: false,
@@ -135,7 +140,15 @@ class FormPage extends _common.Com {
135
140
  this.setState({
136
141
  submiting: true
137
142
  });
138
- let res = await this.props.store.submitForm2(this.props.store.matchAccount().id, this.props.token, this.state.submission);
143
+ let res;
144
+ if (this.props.token) {
145
+ res = await this.props.store.submitForm2(this.props.store.matchAccount().id, this.props.token, this.state.submission);
146
+ } else {
147
+ res = await this.props.store.submitPublicForm(this.props.formId, {
148
+ values: _index.default.get(this.state.submission, 'values') || [],
149
+ page_url: document.referrer || location.href
150
+ });
151
+ }
139
152
  if (res.error) {
140
153
  this.setState({
141
154
  submiting: false,