@product7/product7-js 0.7.2 → 0.7.5

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.2",
3
+ "version": "0.7.5",
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,89 +869,22 @@
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;
953
- }
954
-
955
888
  .liveChat-feedback-error {
956
889
  font-size: var(--font-size-xs);
957
890
  color: #ef4444;
@@ -278,10 +278,7 @@ export class LiveChatWidget extends BaseWidget {
278
278
 
279
279
  async _handleStartConversation(messageContent, pendingAttachments) {
280
280
  try {
281
- if (
282
- this.LiveChatState.requireEmailBeforeChat &&
283
- !this.LiveChatState.isIdentified
284
- ) {
281
+ if (!this.LiveChatState.isIdentified) {
285
282
  this.LiveChatState.pendingMessage = {
286
283
  content: messageContent,
287
284
  attachments: pendingAttachments,
@@ -979,9 +976,15 @@ export class LiveChatWidget extends BaseWidget {
979
976
  this.liveChatOptions.textColor = s.text_color;
980
977
  stylesChanged = true;
981
978
  }
982
- if (s.theme && !this._hasExplicitOption('theme')) {
979
+ let themeChanged = false;
980
+ if (
981
+ s.theme &&
982
+ !this._hasExplicitOption('theme') &&
983
+ s.theme !== this.liveChatOptions.theme
984
+ ) {
983
985
  this.liveChatOptions.theme = s.theme;
984
986
  stylesChanged = true;
987
+ themeChanged = true;
985
988
  }
986
989
  if (stylesChanged) {
987
990
  applyliveChatCustomStyles({
@@ -991,6 +994,9 @@ export class LiveChatWidget extends BaseWidget {
991
994
  theme: this.liveChatOptions.theme,
992
995
  });
993
996
  }
997
+ if (themeChanged && this._widgetContainer) {
998
+ this._widgetContainer.className = `liveChat-widget theme-${this.liveChatOptions.theme}`;
999
+ }
994
1000
 
995
1001
  // Launcher position & padding
996
1002
  if (s.launcher_position && !this._hasExplicitOption('position')) {
@@ -1049,6 +1055,36 @@ export class LiveChatWidget extends BaseWidget {
1049
1055
  this.LiveChatState.homeModuleEnabled !== false ? 'home' : 'help';
1050
1056
  }
1051
1057
  }
1058
+ if (
1059
+ typeof s.help_module_enabled === 'boolean' &&
1060
+ !this._hasExplicitOption('enableHelp')
1061
+ ) {
1062
+ this.LiveChatState.enableHelp = s.help_module_enabled;
1063
+ if (
1064
+ !s.help_module_enabled &&
1065
+ this.LiveChatState.currentView === 'help'
1066
+ ) {
1067
+ this.LiveChatState.currentView =
1068
+ this.LiveChatState.homeModuleEnabled !== false
1069
+ ? 'home'
1070
+ : 'messages';
1071
+ }
1072
+ }
1073
+ if (
1074
+ typeof s.changelog_module_enabled === 'boolean' &&
1075
+ !this._hasExplicitOption('enableChangelog')
1076
+ ) {
1077
+ this.LiveChatState.enableChangelog = s.changelog_module_enabled;
1078
+ if (
1079
+ !s.changelog_module_enabled &&
1080
+ this.LiveChatState.currentView === 'changelog'
1081
+ ) {
1082
+ this.LiveChatState.currentView =
1083
+ this.LiveChatState.homeModuleEnabled !== false
1084
+ ? 'home'
1085
+ : 'messages';
1086
+ }
1087
+ }
1052
1088
 
1053
1089
  // Feature flags
1054
1090
  if (
@@ -1066,6 +1102,12 @@ export class LiveChatWidget extends BaseWidget {
1066
1102
  ) {
1067
1103
  this.LiveChatState.requireEmailBeforeChat = s.require_email_before_chat;
1068
1104
  }
1105
+ if (
1106
+ typeof s.allow_anonymous_chat === 'boolean' &&
1107
+ !this._hasExplicitOption('allowAnonymousChat')
1108
+ ) {
1109
+ this.LiveChatState.allowAnonymousChat = s.allow_anonymous_chat;
1110
+ }
1069
1111
  if (
1070
1112
  typeof s.allow_attachments === 'boolean' &&
1071
1113
  !this._hasExplicitOption('allowAttachments')
@@ -31,6 +31,7 @@
31
31
  this.messagesModuleEnabled = options.messagesModuleEnabled !== false;
32
32
 
33
33
  this.requireEmailBeforeChat = options.requireEmailBeforeChat || false;
34
+ this.allowAnonymousChat = options.allowAnonymousChat !== false;
34
35
  this.allowAttachments = options.allowAttachments !== false;
35
36
  this.allowEmoji = options.allowEmoji !== false;
36
37
  this.showReplyTime = options.showReplyTime !== false;
@@ -23,18 +23,23 @@ export class FeedbackFormView {
23
23
  </div>
24
24
  <div class="liveChat-feedback-body">
25
25
  <p class="liveChat-feedback-prompt">Share your thoughts with us. We read every message.</p>
26
- <input
27
- type="text"
28
- class="liveChat-feedback-input"
29
- placeholder="Title"
30
- />
31
- <textarea
32
- class="liveChat-feedback-textarea"
33
- placeholder="Your feedback..."
34
- rows="5"
35
- ></textarea>
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>
36
41
  <span class="liveChat-feedback-error" style="display:none;"></span>
37
- <button class="liveChat-feedback-submit">Send feedback</button>
42
+ <button class="sdk-btn-primary sdk-btn-block liveChat-feedback-submit">Send feedback</button>
38
43
  </div>
39
44
  `;
40
45
  this._attachEvents();
@@ -1,4 +1,4 @@
1
- export class PreChatFormView {
1
+ export class PreChatFormView {
2
2
  constructor(state, options = {}) {
3
3
  this.state = state;
4
4
  this.options = options;
@@ -13,20 +13,31 @@
13
13
  return this.element;
14
14
  }
15
15
 
16
+ _isNameRequired() {
17
+ return this.state.allowAnonymousChat === false;
18
+ }
19
+
16
20
  _updateContent() {
21
+ const nameRequired = this._isNameRequired();
22
+ const namePlaceholder = nameRequired ? 'Your name' : 'Your name (optional)';
23
+ const subtitle = nameRequired
24
+ ? 'Enter your name and email so we can get back to you.'
25
+ : 'Enter your email so we can get back to you.';
26
+
17
27
  this.element.innerHTML = `
18
28
  <div class="liveChat-prechat-overlay">
19
29
  <div class="liveChat-prechat-card">
20
30
  <h4 class="liveChat-prechat-title">Before we continue</h4>
21
- <p class="liveChat-prechat-subtitle">Enter your details so we can get back to you.</p>
31
+ <p class="liveChat-prechat-subtitle">${subtitle}</p>
22
32
  <form class="liveChat-prechat-form" novalidate>
23
33
  <div class="liveChat-prechat-field">
24
34
  <input
25
35
  type="text"
26
36
  name="name"
27
37
  class="liveChat-prechat-input"
28
- placeholder="Your name"
38
+ placeholder="${namePlaceholder}"
29
39
  autocomplete="name"
40
+ ${nameRequired ? 'required' : ''}
30
41
  />
31
42
  </div>
32
43
  <div class="liveChat-prechat-field">
@@ -38,8 +49,8 @@
38
49
  autocomplete="email"
39
50
  required
40
51
  />
41
- <span class="liveChat-prechat-error" style="display:none;"></span>
42
52
  </div>
53
+ <span class="liveChat-prechat-error" style="display:none;"></span>
43
54
  <button type="submit" class="liveChat-prechat-submit">
44
55
  Start chat
45
56
  </button>
@@ -59,6 +70,15 @@
59
70
  });
60
71
  }
61
72
 
73
+ _validate(nameRequired, name, email) {
74
+ if (nameRequired && !name) return { msg: 'Please enter your name.', field: 'name' };
75
+ if (!email) return { msg: 'Please enter your email address.', field: 'email' };
76
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
77
+ return { msg: 'Please enter a valid email address.', field: 'email' };
78
+ }
79
+ return null;
80
+ }
81
+
62
82
  async _handleSubmit() {
63
83
  if (this._isSubmitting) return;
64
84
 
@@ -69,11 +89,13 @@
69
89
 
70
90
  const email = emailInput.value.trim();
71
91
  const name = nameInput.value.trim();
92
+ const nameRequired = this._isNameRequired();
72
93
 
73
- if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
74
- errorEl.textContent = 'Please enter a valid email address.';
94
+ const error = this._validate(nameRequired, name, email);
95
+ if (error) {
96
+ errorEl.textContent = error.msg;
75
97
  errorEl.style.display = 'block';
76
- emailInput.focus();
98
+ (error.field === 'name' ? nameInput : emailInput).focus();
77
99
  return;
78
100
  }
79
101
 
@@ -89,7 +111,7 @@
89
111
  if (this.options.onIdentifyContact) {
90
112
  await this.options.onIdentifyContact({
91
113
  name: name || undefined,
92
- email,
114
+ email: email || undefined,
93
115
  });
94
116
  }
95
117