@product7/product7-js 0.7.0 → 0.7.3

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.7.0",
3
+ "version": "0.7.3",
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",
@@ -869,87 +869,26 @@
869
869
  .liveChat-feedback-body {
870
870
  display: flex;
871
871
  flex-direction: column;
872
- gap: var(--spacing-4);
872
+ gap: var(--spacing-3);
873
873
  padding: var(--spacing-5) var(--spacing-4);
874
874
  flex: 1;
875
875
  overflow-y: auto;
876
876
  }
877
877
 
878
+ .liveChat-feedback-body .sdk-form-group {
879
+ margin-bottom: 0;
880
+ }
881
+
878
882
  .liveChat-feedback-prompt {
879
883
  margin: 0;
880
884
  font-size: var(--font-size-sm);
881
885
  color: var(--text-secondary);
882
886
  }
883
887
 
884
-
885
- .liveChat-feedback-input {
886
- width: 100%;
887
- border: 1px solid var(--border-color);
888
- border-radius: var(--radius-md);
889
- padding: var(--spacing-3);
890
- font-size: var(--font-size-sm);
891
- font-family: inherit;
892
- color: var(--text-primary);
893
- background: var(--msg-bg);
894
- box-sizing: border-box;
895
- transition: border-color var(--transition-fast);
896
- }
897
-
898
- .liveChat-feedback-input::placeholder {
899
- color: var(--msg-text-secondary);
900
- }
901
-
902
- .liveChat-feedback-input:focus {
903
- outline: none;
904
- border-color: var(--color-primary);
905
- }
906
-
907
- .liveChat-feedback-textarea {
908
- width: 100%;
909
- resize: none;
910
- border: 1px solid var(--border-color);
911
- border-radius: var(--radius-md);
912
- padding: var(--spacing-3);
913
- font-size: var(--font-size-sm);
914
- font-family: inherit;
915
- color: var(--text-primary);
916
- background: var(--msg-bg);
917
- box-sizing: border-box;
918
- transition: border-color var(--transition-fast);
919
- }
920
-
921
- .liveChat-feedback-textarea::placeholder {
922
- color: var(--msg-text-secondary);
923
- }
924
-
925
- .liveChat-feedback-textarea:focus {
926
- outline: none;
927
- border-color: var(--color-primary);
928
- }
929
-
930
- .liveChat-feedback-submit {
931
- display: flex;
932
- align-items: center;
933
- justify-content: center;
934
- padding: var(--spacing-3);
935
- border-radius: var(--radius-md);
936
- font-size: var(--font-size-sm);
937
- font-weight: var(--font-weight-medium);
938
- font-family: inherit;
939
- cursor: pointer;
940
- border: none;
941
- background: var(--color-primary);
942
- color: #ffffff;
943
- transition: all var(--transition-fast);
944
- }
945
-
946
- .liveChat-feedback-submit:hover:not(:disabled) {
947
- background: var(--color-primary-hover);
948
- }
949
-
950
- .liveChat-feedback-submit:disabled {
951
- opacity: 0.5;
952
- cursor: not-allowed;
888
+ .liveChat-feedback-error {
889
+ font-size: var(--font-size-xs);
890
+ color: #ef4444;
891
+ margin-top: calc(var(--spacing-2) * -1);
953
892
  }
954
893
 
955
894
  .liveChat-feedback-thankyou {
@@ -963,9 +902,15 @@
963
902
  gap: var(--spacing-3);
964
903
  }
965
904
 
966
- .liveChat-feedback-thankyou-emoji {
967
- font-size: 48px;
968
- line-height: 1;
905
+ .liveChat-feedback-success-icon {
906
+ width: 56px;
907
+ height: 56px;
908
+ border-radius: 50%;
909
+ background: #037F0C;
910
+ display: flex;
911
+ align-items: center;
912
+ justify-content: center;
913
+ margin-bottom: var(--spacing-2);
969
914
  }
970
915
 
971
916
  .liveChat-feedback-thankyou h3 {
@@ -4,10 +4,10 @@ export async function getIpInfo() {
4
4
  if (_cached) return _cached;
5
5
 
6
6
  try {
7
- const res = await fetch('https://ipwho.is/');
7
+ const res = await fetch('https://ipapi.co/json/');
8
8
  if (!res.ok) return null;
9
9
  const data = await res.json();
10
- if (data.success) {
10
+ if (data.ip) {
11
11
  _cached = data;
12
12
  }
13
13
  return _cached;
@@ -149,6 +149,24 @@ export class LiveChatWidget extends BaseWidget {
149
149
  }
150
150
  }
151
151
 
152
+ async _handleSubmitFeedback({ title, message }) {
153
+ const payload = {
154
+ title: title || 'Feedback',
155
+ content: message,
156
+ board_id:
157
+ this.liveChatOptions.feedbackBoardName || this.sdk.config.boardName,
158
+ };
159
+
160
+ const response = await this.apiService.submitFeedback(payload);
161
+
162
+ this.sdk.eventBus.emit('feedback:submitted', {
163
+ widget: this,
164
+ feedback: response,
165
+ });
166
+
167
+ return response;
168
+ }
169
+
152
170
  _render() {
153
171
  const container = document.createElement('div');
154
172
  container.className = `liveChat-widget theme-${this.liveChatOptions.theme}`;
@@ -201,6 +219,7 @@ export class LiveChatWidget extends BaseWidget {
201
219
  onFeedbackClick:
202
220
  this.liveChatOptions.onFeedbackClick ||
203
221
  (this._feedbackWidget ? () => this._feedbackWidget.open() : null),
222
+ onSubmitFeedback: this._handleSubmitFeedback.bind(this),
204
223
  onArticleClick: this.liveChatOptions.onArticleClick,
205
224
  onChangelogClick: this.liveChatOptions.onChangelogClick,
206
225
  });
@@ -4,7 +4,6 @@ export class FeedbackFormView {
4
4
  this.options = options;
5
5
  this.element = null;
6
6
  this._isSubmitting = false;
7
- this._selectedRating = null;
8
7
  }
9
8
 
10
9
  render() {
@@ -24,17 +23,23 @@ export class FeedbackFormView {
24
23
  </div>
25
24
  <div class="liveChat-feedback-body">
26
25
  <p class="liveChat-feedback-prompt">Share your thoughts with us. We read every message.</p>
27
- <input
28
- type="text"
29
- class="liveChat-feedback-input"
30
- placeholder="Title"
31
- />
32
- <textarea
33
- class="liveChat-feedback-textarea"
34
- placeholder="Your feedback..."
35
- rows="5"
36
- ></textarea>
37
- <button class="liveChat-feedback-submit">Send feedback</button>
26
+ <div class="sdk-form-group">
27
+ <label class="sdk-label">Title <span class="sdk-required">*</span></label>
28
+ <input
29
+ type="text"
30
+ class="sdk-input liveChat-feedback-input"
31
+ placeholder="Brief description of your feedback"
32
+ />
33
+ </div>
34
+ <div class="sdk-form-group">
35
+ <label class="sdk-label">Message <span class="sdk-required">*</span></label>
36
+ <textarea
37
+ class="sdk-textarea liveChat-feedback-textarea"
38
+ placeholder="Tell us what you think..."
39
+ ></textarea>
40
+ </div>
41
+ <span class="liveChat-feedback-error" style="display:none;"></span>
42
+ <button class="sdk-btn-primary sdk-btn-block liveChat-feedback-submit">Send feedback</button>
38
43
  </div>
39
44
  `;
40
45
  this._attachEvents();
@@ -49,9 +54,13 @@ export class FeedbackFormView {
49
54
  <span class="liveChat-feedback-title">Leave us feedback</span>
50
55
  </div>
51
56
  <div class="liveChat-feedback-thankyou">
52
- <span class="liveChat-feedback-thankyou-emoji">🙏</span>
53
- <h3>Thanks for your feedback!</h3>
54
- <p>We appreciate you taking the time to share your thoughts.</p>
57
+ <div class="liveChat-feedback-success-icon">
58
+ <svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="none" stroke="#ffffff" stroke-width="24" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 256 256">
59
+ <polyline points="216,72 96,192 40,136"/>
60
+ </svg>
61
+ </div>
62
+ <h3>Thank you!</h3>
63
+ <p>Your feedback has been submitted successfully.</p>
55
64
  <button class="liveChat-feedback-done-btn">Done</button>
56
65
  </div>
57
66
  `;
@@ -77,7 +86,36 @@ export class FeedbackFormView {
77
86
  });
78
87
  }
79
88
 
89
+ _showError(text) {
90
+ const errorEl = this.element.querySelector('.liveChat-feedback-error');
91
+ if (errorEl) {
92
+ errorEl.textContent = text;
93
+ errorEl.style.display = 'block';
94
+ }
95
+ }
96
+
97
+ _hideError() {
98
+ const errorEl = this.element.querySelector('.liveChat-feedback-error');
99
+ if (errorEl) {
100
+ errorEl.style.display = 'none';
101
+ }
102
+ }
103
+
80
104
  async _submit(title, message) {
105
+ this._hideError();
106
+
107
+ if (!title) {
108
+ this._showError('Please enter a title.');
109
+ this.element.querySelector('.liveChat-feedback-input').focus();
110
+ return;
111
+ }
112
+
113
+ if (!message) {
114
+ this._showError('Please enter your feedback message.');
115
+ this.element.querySelector('.liveChat-feedback-textarea').focus();
116
+ return;
117
+ }
118
+
81
119
  this._isSubmitting = true;
82
120
  const submitBtn = this.element.querySelector('.liveChat-feedback-submit');
83
121
  if (submitBtn) {
@@ -89,11 +127,16 @@ export class FeedbackFormView {
89
127
  if (this.options.onSubmitFeedback) {
90
128
  await this.options.onSubmitFeedback({ title, message });
91
129
  }
130
+ this._renderThankYou();
92
131
  } catch (e) {
93
132
  console.warn('[FeedbackFormView] Submit error:', e);
133
+ this._isSubmitting = false;
134
+ this._showError('Failed to submit feedback. Please try again.');
135
+ if (submitBtn) {
136
+ submitBtn.disabled = false;
137
+ submitBtn.textContent = 'Send feedback';
138
+ }
94
139
  }
95
-
96
- this._renderThankYou();
97
140
  }
98
141
 
99
142
  destroy() {