@product7/product7-js 0.4.5 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@product7/product7-js",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "JavaScript SDK for integrating Product7 feedback widgets into any website",
5
5
  "main": "dist/product7-js.js",
6
6
  "module": "src/index.js",
@@ -768,14 +768,46 @@ export const messengerComponentsStyles = `
768
768
  line-height: var(--line-height-relaxed);
769
769
  }
770
770
 
771
- .messenger-prechat-actions {
771
+ .messenger-prechat-form {
772
772
  display: flex;
773
773
  flex-direction: column;
774
- gap: var(--spacing-2);
774
+ gap: var(--spacing-3);
775
775
  }
776
776
 
777
- .messenger-prechat-yes,
778
- .messenger-prechat-no {
777
+ .messenger-prechat-field {
778
+ display: flex;
779
+ flex-direction: column;
780
+ gap: var(--spacing-1);
781
+ }
782
+
783
+ .messenger-prechat-input {
784
+ width: 100%;
785
+ padding: var(--spacing-3) var(--spacing-4);
786
+ border: 1px solid var(--msg-border);
787
+ border-radius: var(--radius-md);
788
+ font-size: var(--font-size-sm);
789
+ font-family: inherit;
790
+ background: var(--msg-bg-surface);
791
+ color: var(--msg-text);
792
+ outline: none;
793
+ transition: border-color var(--transition-fast);
794
+ box-sizing: border-box;
795
+ }
796
+
797
+ .messenger-prechat-input::placeholder {
798
+ color: var(--msg-text-secondary);
799
+ }
800
+
801
+ .messenger-prechat-input:focus {
802
+ border-color: var(--color-primary);
803
+ }
804
+
805
+ .messenger-prechat-error {
806
+ font-size: var(--font-size-xs);
807
+ color: #dc2626;
808
+ }
809
+
810
+ .messenger-prechat-submit {
779
811
  display: flex;
780
812
  align-items: center;
781
813
  justify-content: center;
@@ -789,40 +821,22 @@ export const messengerComponentsStyles = `
789
821
  transition: all var(--transition-fast);
790
822
  border: none;
791
823
  width: 100%;
792
- }
793
-
794
- .messenger-prechat-yes {
795
824
  background: var(--color-primary);
796
825
  color: #ffffff;
826
+ margin-top: var(--spacing-1);
797
827
  }
798
828
 
799
- .messenger-prechat-yes:hover {
829
+ .messenger-prechat-submit:hover {
800
830
  background: var(--color-primary-hover);
801
831
  }
802
832
 
803
- .messenger-prechat-yes:active {
833
+ .messenger-prechat-submit:active {
804
834
  transform: translateY(1px);
805
835
  transition-duration: 100ms;
806
836
  }
807
837
 
808
- .messenger-prechat-yes:disabled {
838
+ .messenger-prechat-submit:disabled {
809
839
  opacity: 0.7;
810
840
  cursor: not-allowed;
811
841
  }
812
-
813
- .messenger-prechat-no {
814
- background: var(--msg-bg-surface);
815
- color: var(--msg-text-secondary);
816
- border: 1px solid var(--msg-border);
817
- }
818
-
819
- .messenger-prechat-no:hover {
820
- background: var(--msg-bg-hover);
821
- color: var(--msg-text);
822
- }
823
-
824
- .messenger-prechat-no:active {
825
- transform: translateY(1px);
826
- transition-duration: 100ms;
827
- }
828
842
  `;
@@ -71,6 +71,8 @@ export class MessengerWidget extends BaseWidget {
71
71
  onChangelogClick: options.onChangelogClick || null,
72
72
  };
73
73
 
74
+ const sdkMetadata = this.sdk?.apiService?.getMetadata() || null;
75
+
74
76
  this.messengerState = new MessengerState({
75
77
  teamName: this.messengerOptions.teamName,
76
78
  teamAvatars: this.messengerOptions.teamAvatars,
@@ -80,7 +82,7 @@ export class MessengerWidget extends BaseWidget {
80
82
  responseTime: this.messengerOptions.responseTime,
81
83
  enableHelp: this.messengerOptions.enableHelp,
82
84
  enableChangelog: this.messengerOptions.enableChangelog,
83
- metadata: this.sdk?.apiService?.getMetadata() || null,
85
+ metadata: sdkMetadata,
84
86
  urls: {
85
87
  feedback: this.messengerOptions.feedbackUrl,
86
88
  changelog: this.messengerOptions.changelogUrl,
@@ -89,6 +91,11 @@ export class MessengerWidget extends BaseWidget {
89
91
  },
90
92
  });
91
93
 
94
+ // If identify() was called before this widget was created, pre-seed identity
95
+ if (this.sdk?.identified && sdkMetadata) {
96
+ this.messengerState.isIdentified = true;
97
+ }
98
+
92
99
  this.launcher = null;
93
100
  this.panel = null;
94
101
  this.wsService = null;
@@ -9,9 +9,7 @@ export class PreChatFormView {
9
9
  render() {
10
10
  this.element = document.createElement('div');
11
11
  this.element.className = 'messenger-view messenger-prechat-view';
12
-
13
12
  this._updateContent();
14
-
15
13
  return this.element;
16
14
  }
17
15
 
@@ -20,20 +18,35 @@ export class PreChatFormView {
20
18
  <div class="messenger-prechat-overlay">
21
19
  <div class="messenger-prechat-card">
22
20
  <div class="messenger-prechat-icon">
23
- <iconify-icon icon="ph:bell-ringing-duotone" width="36" height="36"></iconify-icon>
21
+ <iconify-icon icon="ph:chat-teardrop-dots-duotone" width="36" height="36"></iconify-icon>
24
22
  </div>
25
- <h4 class="messenger-prechat-title">Get notified when we reply</h4>
26
- <p class="messenger-prechat-subtitle">We'll send you an email so you never miss a response.</p>
27
- <div class="messenger-prechat-actions">
28
- <button type="button" class="messenger-prechat-yes">
29
- <iconify-icon icon="ph:bell-ringing-duotone" width="16" height="16"></iconify-icon>
30
- Yes, notify me
23
+ <h4 class="messenger-prechat-title">Before we continue</h4>
24
+ <p class="messenger-prechat-subtitle">Enter your details so we can get back to you.</p>
25
+ <form class="messenger-prechat-form" novalidate>
26
+ <div class="messenger-prechat-field">
27
+ <input
28
+ type="text"
29
+ name="name"
30
+ class="messenger-prechat-input"
31
+ placeholder="Your name"
32
+ autocomplete="name"
33
+ />
34
+ </div>
35
+ <div class="messenger-prechat-field">
36
+ <input
37
+ type="email"
38
+ name="email"
39
+ class="messenger-prechat-input"
40
+ placeholder="Your email address"
41
+ autocomplete="email"
42
+ required
43
+ />
44
+ <span class="messenger-prechat-error" style="display:none;"></span>
45
+ </div>
46
+ <button type="submit" class="messenger-prechat-submit">
47
+ Start chat
31
48
  </button>
32
- <button type="button" class="messenger-prechat-no">
33
- <iconify-icon icon="ph:bell-slash-duotone" width="16" height="16"></iconify-icon>
34
- No thanks
35
- </button>
36
- </div>
49
+ </form>
37
50
  </div>
38
51
  </div>
39
52
  `;
@@ -42,35 +55,45 @@ export class PreChatFormView {
42
55
  }
43
56
 
44
57
  _attachEvents() {
45
- this.element
46
- .querySelector('.messenger-prechat-yes')
47
- .addEventListener('click', async () => {
48
- await this._handleYes();
49
- });
50
-
51
- this.element
52
- .querySelector('.messenger-prechat-no')
53
- .addEventListener('click', () => {
54
- this._handleNo();
55
- });
58
+ const form = this.element.querySelector('.messenger-prechat-form');
59
+ form.addEventListener('submit', async (e) => {
60
+ e.preventDefault();
61
+ await this._handleSubmit();
62
+ });
56
63
  }
57
64
 
58
- async _handleYes() {
65
+ async _handleSubmit() {
59
66
  if (this._isSubmitting) return;
60
- this._isSubmitting = true;
61
67
 
62
- const yesBtn = this.element.querySelector('.messenger-prechat-yes');
63
- yesBtn.disabled = true;
64
- yesBtn.innerHTML = `
68
+ const emailInput = this.element.querySelector('input[name="email"]');
69
+ const nameInput = this.element.querySelector('input[name="name"]');
70
+ const errorEl = this.element.querySelector('.messenger-prechat-error');
71
+ const submitBtn = this.element.querySelector('.messenger-prechat-submit');
72
+
73
+ const email = emailInput.value.trim();
74
+ const name = nameInput.value.trim();
75
+
76
+ if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
77
+ errorEl.textContent = 'Please enter a valid email address.';
78
+ errorEl.style.display = 'block';
79
+ emailInput.focus();
80
+ return;
81
+ }
82
+
83
+ errorEl.style.display = 'none';
84
+ this._isSubmitting = true;
85
+ submitBtn.disabled = true;
86
+ submitBtn.innerHTML = `
65
87
  <iconify-icon icon="ph:circle-notch" width="16" height="16" style="animation: spin 0.8s linear infinite;"></iconify-icon>
66
88
  Just a moment...
67
89
  `;
68
90
 
69
91
  try {
70
- const { name, email } = this.state.metadata || {};
71
-
72
92
  if (this.options.onIdentifyContact) {
73
- await this.options.onIdentifyContact({ name, email });
93
+ await this.options.onIdentifyContact({
94
+ name: name || undefined,
95
+ email,
96
+ });
74
97
  }
75
98
 
76
99
  this.state.setIdentified(true, { name, email });
@@ -88,19 +111,14 @@ export class PreChatFormView {
88
111
  }
89
112
  } catch (error) {
90
113
  console.error('[PreChatFormView] Error:', error);
114
+ errorEl.textContent = 'Something went wrong. Please try again.';
115
+ errorEl.style.display = 'block';
91
116
  this._isSubmitting = false;
92
- yesBtn.disabled = false;
93
- yesBtn.innerHTML = `
94
- <iconify-icon icon="ph:bell-ringing-duotone" width="16" height="16"></iconify-icon>
95
- Yes, notify me
96
- `;
117
+ submitBtn.disabled = false;
118
+ submitBtn.textContent = 'Start chat';
97
119
  }
98
120
  }
99
121
 
100
- _handleNo() {
101
- this.state.setView('chat');
102
- }
103
-
104
122
  destroy() {
105
123
  if (this.element && this.element.parentNode) {
106
124
  this.element.parentNode.removeChild(this.element);