@product7/product7-js 0.4.4 → 0.4.6

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.
@@ -1130,6 +1130,7 @@
1130
1130
  return {
1131
1131
  sessionToken: this.sessionToken,
1132
1132
  config: initData.config,
1133
+ widgets: initData.widgets,
1133
1134
  expiresIn: initData.expiresIn,
1134
1135
  status: initData.status,
1135
1136
  message: initData.message,
@@ -1150,8 +1151,23 @@
1150
1151
  ? response.data
1151
1152
  : response || {};
1152
1153
 
1153
- const sessionToken = payload.session_token || payload.sessionToken;
1154
- const expiresIn = Number(payload.expires_in ?? payload.expiresIn);
1154
+ const configData =
1155
+ payload.config && typeof payload.config === 'object'
1156
+ ? payload.config
1157
+ : {};
1158
+
1159
+ const sessionToken =
1160
+ payload.session_token ||
1161
+ payload.sessionToken ||
1162
+ configData.session_token ||
1163
+ configData.sessionToken;
1164
+
1165
+ const expiresIn = Number(
1166
+ payload.expires_in ??
1167
+ payload.expiresIn ??
1168
+ configData.expires_in ??
1169
+ configData.expiresIn
1170
+ );
1155
1171
 
1156
1172
  if (!sessionToken) {
1157
1173
  throw new APIError(500, 'Invalid init response: missing session_token');
@@ -1164,11 +1180,17 @@
1164
1180
  return {
1165
1181
  sessionToken,
1166
1182
  expiresIn,
1167
- config:
1168
- payload.config && typeof payload.config === 'object'
1169
- ? payload.config
1170
- : {},
1171
- configVersion: payload.config_version ?? payload.configVersion ?? null,
1183
+ config: configData,
1184
+ widgets:
1185
+ payload.widgets && typeof payload.widgets === 'object'
1186
+ ? payload.widgets
1187
+ : null,
1188
+ configVersion:
1189
+ configData.config_version ??
1190
+ configData.configVersion ??
1191
+ payload.config_version ??
1192
+ payload.configVersion ??
1193
+ null,
1172
1194
  status: response?.status ?? payload?.status ?? true,
1173
1195
  message: response?.message ?? payload?.message ?? null,
1174
1196
  };
@@ -4190,14 +4212,46 @@
4190
4212
  line-height: var(--line-height-relaxed);
4191
4213
  }
4192
4214
 
4193
- .messenger-prechat-actions {
4215
+ .messenger-prechat-form {
4194
4216
  display: flex;
4195
4217
  flex-direction: column;
4196
- gap: var(--spacing-2);
4218
+ gap: var(--spacing-3);
4197
4219
  }
4198
4220
 
4199
- .messenger-prechat-yes,
4200
- .messenger-prechat-no {
4221
+ .messenger-prechat-field {
4222
+ display: flex;
4223
+ flex-direction: column;
4224
+ gap: var(--spacing-1);
4225
+ }
4226
+
4227
+ .messenger-prechat-input {
4228
+ width: 100%;
4229
+ padding: var(--spacing-3) var(--spacing-4);
4230
+ border: 1px solid var(--msg-border);
4231
+ border-radius: var(--radius-md);
4232
+ font-size: var(--font-size-sm);
4233
+ font-family: inherit;
4234
+ background: var(--msg-bg-surface);
4235
+ color: var(--msg-text);
4236
+ outline: none;
4237
+ transition: border-color var(--transition-fast);
4238
+ box-sizing: border-box;
4239
+ }
4240
+
4241
+ .messenger-prechat-input::placeholder {
4242
+ color: var(--msg-text-secondary);
4243
+ }
4244
+
4245
+ .messenger-prechat-input:focus {
4246
+ border-color: var(--color-primary);
4247
+ }
4248
+
4249
+ .messenger-prechat-error {
4250
+ font-size: var(--font-size-xs);
4251
+ color: #dc2626;
4252
+ }
4253
+
4254
+ .messenger-prechat-submit {
4201
4255
  display: flex;
4202
4256
  align-items: center;
4203
4257
  justify-content: center;
@@ -4211,42 +4265,24 @@
4211
4265
  transition: all var(--transition-fast);
4212
4266
  border: none;
4213
4267
  width: 100%;
4214
- }
4215
-
4216
- .messenger-prechat-yes {
4217
4268
  background: var(--color-primary);
4218
4269
  color: #ffffff;
4270
+ margin-top: var(--spacing-1);
4219
4271
  }
4220
4272
 
4221
- .messenger-prechat-yes:hover {
4273
+ .messenger-prechat-submit:hover {
4222
4274
  background: var(--color-primary-hover);
4223
4275
  }
4224
4276
 
4225
- .messenger-prechat-yes:active {
4277
+ .messenger-prechat-submit:active {
4226
4278
  transform: translateY(1px);
4227
4279
  transition-duration: 100ms;
4228
4280
  }
4229
4281
 
4230
- .messenger-prechat-yes:disabled {
4282
+ .messenger-prechat-submit:disabled {
4231
4283
  opacity: 0.7;
4232
4284
  cursor: not-allowed;
4233
4285
  }
4234
-
4235
- .messenger-prechat-no {
4236
- background: var(--msg-bg-surface);
4237
- color: var(--msg-text-secondary);
4238
- border: 1px solid var(--msg-border);
4239
- }
4240
-
4241
- .messenger-prechat-no:hover {
4242
- background: var(--msg-bg-hover);
4243
- color: var(--msg-text);
4244
- }
4245
-
4246
- .messenger-prechat-no:active {
4247
- transform: translateY(1px);
4248
- transition-duration: 100ms;
4249
- }
4250
4286
  `;
4251
4287
 
4252
4288
  const messengerCoreStyles = `
@@ -11180,9 +11216,7 @@
11180
11216
  render() {
11181
11217
  this.element = document.createElement('div');
11182
11218
  this.element.className = 'messenger-view messenger-prechat-view';
11183
-
11184
11219
  this._updateContent();
11185
-
11186
11220
  return this.element;
11187
11221
  }
11188
11222
 
@@ -11191,20 +11225,35 @@
11191
11225
  <div class="messenger-prechat-overlay">
11192
11226
  <div class="messenger-prechat-card">
11193
11227
  <div class="messenger-prechat-icon">
11194
- <iconify-icon icon="ph:bell-ringing-duotone" width="36" height="36"></iconify-icon>
11228
+ <iconify-icon icon="ph:chat-teardrop-dots-duotone" width="36" height="36"></iconify-icon>
11195
11229
  </div>
11196
- <h4 class="messenger-prechat-title">Get notified when we reply</h4>
11197
- <p class="messenger-prechat-subtitle">We'll send you an email so you never miss a response.</p>
11198
- <div class="messenger-prechat-actions">
11199
- <button type="button" class="messenger-prechat-yes">
11200
- <iconify-icon icon="ph:bell-ringing-duotone" width="16" height="16"></iconify-icon>
11201
- Yes, notify me
11202
- </button>
11203
- <button type="button" class="messenger-prechat-no">
11204
- <iconify-icon icon="ph:bell-slash-duotone" width="16" height="16"></iconify-icon>
11205
- No thanks
11230
+ <h4 class="messenger-prechat-title">Before we continue</h4>
11231
+ <p class="messenger-prechat-subtitle">Enter your details so we can get back to you.</p>
11232
+ <form class="messenger-prechat-form" novalidate>
11233
+ <div class="messenger-prechat-field">
11234
+ <input
11235
+ type="text"
11236
+ name="name"
11237
+ class="messenger-prechat-input"
11238
+ placeholder="Your name"
11239
+ autocomplete="name"
11240
+ />
11241
+ </div>
11242
+ <div class="messenger-prechat-field">
11243
+ <input
11244
+ type="email"
11245
+ name="email"
11246
+ class="messenger-prechat-input"
11247
+ placeholder="Your email address"
11248
+ autocomplete="email"
11249
+ required
11250
+ />
11251
+ <span class="messenger-prechat-error" style="display:none;"></span>
11252
+ </div>
11253
+ <button type="submit" class="messenger-prechat-submit">
11254
+ Start chat
11206
11255
  </button>
11207
- </div>
11256
+ </form>
11208
11257
  </div>
11209
11258
  </div>
11210
11259
  `;
@@ -11213,35 +11262,45 @@
11213
11262
  }
11214
11263
 
11215
11264
  _attachEvents() {
11216
- this.element
11217
- .querySelector('.messenger-prechat-yes')
11218
- .addEventListener('click', async () => {
11219
- await this._handleYes();
11220
- });
11221
-
11222
- this.element
11223
- .querySelector('.messenger-prechat-no')
11224
- .addEventListener('click', () => {
11225
- this._handleNo();
11226
- });
11265
+ const form = this.element.querySelector('.messenger-prechat-form');
11266
+ form.addEventListener('submit', async (e) => {
11267
+ e.preventDefault();
11268
+ await this._handleSubmit();
11269
+ });
11227
11270
  }
11228
11271
 
11229
- async _handleYes() {
11272
+ async _handleSubmit() {
11230
11273
  if (this._isSubmitting) return;
11231
- this._isSubmitting = true;
11232
11274
 
11233
- const yesBtn = this.element.querySelector('.messenger-prechat-yes');
11234
- yesBtn.disabled = true;
11235
- yesBtn.innerHTML = `
11275
+ const emailInput = this.element.querySelector('input[name="email"]');
11276
+ const nameInput = this.element.querySelector('input[name="name"]');
11277
+ const errorEl = this.element.querySelector('.messenger-prechat-error');
11278
+ const submitBtn = this.element.querySelector('.messenger-prechat-submit');
11279
+
11280
+ const email = emailInput.value.trim();
11281
+ const name = nameInput.value.trim();
11282
+
11283
+ if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
11284
+ errorEl.textContent = 'Please enter a valid email address.';
11285
+ errorEl.style.display = 'block';
11286
+ emailInput.focus();
11287
+ return;
11288
+ }
11289
+
11290
+ errorEl.style.display = 'none';
11291
+ this._isSubmitting = true;
11292
+ submitBtn.disabled = true;
11293
+ submitBtn.innerHTML = `
11236
11294
  <iconify-icon icon="ph:circle-notch" width="16" height="16" style="animation: spin 0.8s linear infinite;"></iconify-icon>
11237
11295
  Just a moment...
11238
11296
  `;
11239
11297
 
11240
11298
  try {
11241
- const { name, email } = this.state.metadata || {};
11242
-
11243
11299
  if (this.options.onIdentifyContact) {
11244
- await this.options.onIdentifyContact({ name, email });
11300
+ await this.options.onIdentifyContact({
11301
+ name: name || undefined,
11302
+ email,
11303
+ });
11245
11304
  }
11246
11305
 
11247
11306
  this.state.setIdentified(true, { name, email });
@@ -11259,19 +11318,14 @@
11259
11318
  }
11260
11319
  } catch (error) {
11261
11320
  console.error('[PreChatFormView] Error:', error);
11321
+ errorEl.textContent = 'Something went wrong. Please try again.';
11322
+ errorEl.style.display = 'block';
11262
11323
  this._isSubmitting = false;
11263
- yesBtn.disabled = false;
11264
- yesBtn.innerHTML = `
11265
- <iconify-icon icon="ph:bell-ringing-duotone" width="16" height="16"></iconify-icon>
11266
- Yes, notify me
11267
- `;
11324
+ submitBtn.disabled = false;
11325
+ submitBtn.textContent = 'Start chat';
11268
11326
  }
11269
11327
  }
11270
11328
 
11271
- _handleNo() {
11272
- this.state.setView('chat');
11273
- }
11274
-
11275
11329
  destroy() {
11276
11330
  if (this.element && this.element.parentNode) {
11277
11331
  this.element.parentNode.removeChild(this.element);
@@ -11335,6 +11389,8 @@
11335
11389
  onChangelogClick: options.onChangelogClick || null,
11336
11390
  };
11337
11391
 
11392
+ const sdkMetadata = this.sdk?.apiService?.getMetadata() || null;
11393
+
11338
11394
  this.messengerState = new MessengerState({
11339
11395
  teamName: this.messengerOptions.teamName,
11340
11396
  teamAvatars: this.messengerOptions.teamAvatars,
@@ -11344,7 +11400,7 @@
11344
11400
  responseTime: this.messengerOptions.responseTime,
11345
11401
  enableHelp: this.messengerOptions.enableHelp,
11346
11402
  enableChangelog: this.messengerOptions.enableChangelog,
11347
- metadata: this.sdk?.apiService?.getMetadata() || null,
11403
+ metadata: sdkMetadata,
11348
11404
  urls: {
11349
11405
  feedback: this.messengerOptions.feedbackUrl,
11350
11406
  changelog: this.messengerOptions.changelogUrl,
@@ -11353,6 +11409,11 @@
11353
11409
  },
11354
11410
  });
11355
11411
 
11412
+ // If identify() was called before this widget was created, pre-seed identity
11413
+ if (this.sdk?.identified && sdkMetadata) {
11414
+ this.messengerState.isIdentified = true;
11415
+ }
11416
+
11356
11417
  this.launcher = null;
11357
11418
  this.panel = null;
11358
11419
  this.wsService = null;
@@ -13823,8 +13884,12 @@
13823
13884
  try {
13824
13885
  const initData = await this.apiService.init();
13825
13886
 
13826
- if (initData.config) {
13827
- this.config = deepMerge(initData.config, this.config);
13887
+ const serverConfig = initData.config ? { ...initData.config } : {};
13888
+ if (initData.widgets) {
13889
+ serverConfig.widgets = initData.widgets;
13890
+ }
13891
+ if (Object.keys(serverConfig).length > 0) {
13892
+ this.config = deepMerge(serverConfig, this.config);
13828
13893
  }
13829
13894
 
13830
13895
  this.initialized = true;
@@ -13985,6 +14050,8 @@
13985
14050
  surveyConfig.showDescription ?? surveyConfig.show_description,
13986
14051
  customQuestions: surveyConfig.customQuestions || surveyConfig.questions,
13987
14052
  pages: surveyConfig.pages,
14053
+ thankYouConfig:
14054
+ surveyConfig.thankYouConfig || surveyConfig.thank_you_config || null,
13988
14055
  enabled: surveyConfig.enabled,
13989
14056
  ...displayOptions,
13990
14057
  });