@chat21/chat21-web-widget 5.1.33 → 5.1.34-rc1

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 (201) hide show
  1. package/.angular-mcp-cache/package.json +1 -0
  2. package/.cursor/angular18-accessibility-auditor-skill.md +442 -0
  3. package/.cursor/mcp.json +15 -0
  4. package/.github/workflows/docker-community-push-latest.yml +23 -13
  5. package/.github/workflows/docker-image-tag-community-tag-push.yml +22 -12
  6. package/.github/workflows/playwright.yml +27 -0
  7. package/CHANGELOG.md +130 -6
  8. package/Dockerfile +4 -5
  9. package/angular.json +24 -4
  10. package/docs/changelog/this-branch.md +36 -0
  11. package/env.sample +3 -2
  12. package/mocks/voice-websocket-mock/server.cjs +245 -0
  13. package/nginx.conf +22 -2
  14. package/package.json +10 -3
  15. package/playwright.config.ts +41 -0
  16. package/src/app/app.component.html +2 -2
  17. package/src/app/app.component.scss +25 -14
  18. package/src/app/app.component.spec.ts +21 -6
  19. package/src/app/app.component.ts +10 -9
  20. package/src/app/app.module.ts +15 -0
  21. package/src/app/component/conversation-detail/conversation/conversation.component.html +25 -11
  22. package/src/app/component/conversation-detail/conversation/conversation.component.scss +40 -2
  23. package/src/app/component/conversation-detail/conversation/conversation.component.spec.ts +644 -75
  24. package/src/app/component/conversation-detail/conversation/conversation.component.ts +100 -14
  25. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.html +25 -13
  26. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.spec.ts +123 -5
  27. package/src/app/component/conversation-detail/conversation-audio-recorder/conversation-audio-recorder.component.ts +1 -0
  28. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.html +23 -10
  29. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.scss +33 -2
  30. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.spec.ts +242 -149
  31. package/src/app/component/conversation-detail/conversation-content/conversation-content.component.ts +8 -6
  32. package/src/app/component/conversation-detail/conversation-emojii/conversation-emojii.component.spec.ts +53 -3
  33. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.html +200 -96
  34. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.scss +211 -6
  35. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.spec.ts +452 -78
  36. package/src/app/component/conversation-detail/conversation-footer/conversation-footer.component.ts +291 -76
  37. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.html +113 -53
  38. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.scss +12 -4
  39. package/src/app/component/conversation-detail/conversation-header/conversation-header.component.spec.ts +274 -29
  40. package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.html +23 -9
  41. package/src/app/component/conversation-detail/conversation-internal-frame/conversation-internal-frame.component.spec.ts +80 -8
  42. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.html +29 -23
  43. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.spec.ts +185 -16
  44. package/src/app/component/conversation-detail/conversation-preview/conversation-preview.component.ts +34 -14
  45. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.html +46 -0
  46. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.scss +83 -0
  47. package/src/app/component/conversation-detail/stream-audio-spectrum/stream-audio-spectrum.component.ts +192 -0
  48. package/src/app/component/error-alert/error-alert.component.spec.ts +65 -5
  49. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.html +16 -7
  50. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.scss +21 -0
  51. package/src/app/component/eyeeye-catcher-card/eyeeye-catcher-card.component.spec.ts +89 -7
  52. package/src/app/component/form/form-builder/form-builder.component.html +1 -1
  53. package/src/app/component/form/form-builder/form-builder.component.spec.ts +163 -21
  54. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.html +8 -4
  55. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.scss +10 -5
  56. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.spec.ts +90 -16
  57. package/src/app/component/form/inputs/form-checkbox/form-checkbox.component.ts +26 -0
  58. package/src/app/component/form/inputs/form-label/form-label.component.spec.ts +45 -11
  59. package/src/app/component/form/inputs/form-radio-button/form-radio-button.component.spec.ts +24 -6
  60. package/src/app/component/form/inputs/form-select/form-select.component.spec.ts +14 -5
  61. package/src/app/component/form/inputs/form-text/form-text.component.html +14 -12
  62. package/src/app/component/form/inputs/form-text/form-text.component.scss +11 -1
  63. package/src/app/component/form/inputs/form-text/form-text.component.spec.ts +113 -17
  64. package/src/app/component/form/inputs/form-text/form-text.component.ts +35 -3
  65. package/src/app/component/form/inputs/form-textarea/form-textarea.component.html +13 -11
  66. package/src/app/component/form/inputs/form-textarea/form-textarea.component.scss +6 -5
  67. package/src/app/component/form/inputs/form-textarea/form-textarea.component.spec.ts +149 -13
  68. package/src/app/component/form/inputs/form-textarea/form-textarea.component.ts +26 -0
  69. package/src/app/component/form/prechat-form/prechat-form.component.html +14 -11
  70. package/src/app/component/form/prechat-form/prechat-form.component.spec.ts +102 -10
  71. package/src/app/component/form/prechat-form/prechat-form.component.ts +8 -1
  72. package/src/app/component/form/prechat-form-test-mock.ts +35 -0
  73. package/src/app/component/home/home.component.html +38 -31
  74. package/src/app/component/home/home.component.scss +4 -2
  75. package/src/app/component/home/home.component.spec.ts +226 -11
  76. package/src/app/component/home-conversations/home-conversations.component.html +30 -26
  77. package/src/app/component/home-conversations/home-conversations.component.scss +3 -0
  78. package/src/app/component/home-conversations/home-conversations.component.spec.ts +212 -36
  79. package/src/app/component/last-message/last-message.component.html +15 -9
  80. package/src/app/component/last-message/last-message.component.scss +16 -2
  81. package/src/app/component/last-message/last-message.component.spec.ts +204 -23
  82. package/src/app/component/last-message/last-message.component.ts +4 -1
  83. package/src/app/component/launcher-button/launcher-button.component.html +8 -13
  84. package/src/app/component/launcher-button/launcher-button.component.spec.ts +104 -8
  85. package/src/app/component/list-all-conversations/list-all-conversations.component.html +12 -17
  86. package/src/app/component/list-all-conversations/list-all-conversations.component.scss +2 -0
  87. package/src/app/component/list-conversations/list-conversations.component.html +22 -22
  88. package/src/app/component/menu-options/menu-options.component.html +30 -20
  89. package/src/app/component/menu-options/menu-options.component.spec.ts +125 -9
  90. package/src/app/component/message/audio/audio.component.html +13 -15
  91. package/src/app/component/message/audio/audio.component.spec.ts +140 -5
  92. package/src/app/component/message/audio/audio.component.ts +1 -5
  93. package/src/app/component/message/audio-sync/audio-sync.component.html +18 -0
  94. package/src/app/component/message/audio-sync/audio-sync.component.scss +65 -0
  95. package/src/app/component/message/audio-sync/audio-sync.component.spec.ts +103 -0
  96. package/src/app/component/message/audio-sync/audio-sync.component.ts +643 -0
  97. package/src/app/component/message/avatar/avatar.component.html +2 -2
  98. package/src/app/component/message/avatar/avatar.component.spec.ts +99 -7
  99. package/src/app/component/message/bubble-message/bubble-message.component.html +43 -51
  100. package/src/app/component/message/bubble-message/bubble-message.component.scss +59 -1
  101. package/src/app/component/message/bubble-message/bubble-message.component.spec.ts +154 -57
  102. package/src/app/component/message/bubble-message/bubble-message.component.ts +152 -109
  103. package/src/app/component/message/buttons/action-button/action-button.component.html +3 -4
  104. package/src/app/component/message/buttons/action-button/action-button.component.spec.ts +49 -5
  105. package/src/app/component/message/buttons/link-button/link-button.component.scss +5 -8
  106. package/src/app/component/message/buttons/link-button/link-button.component.spec.ts +50 -5
  107. package/src/app/component/message/buttons/text-button/text-button.component.spec.ts +44 -5
  108. package/src/app/component/message/carousel/carousel.component.html +29 -16
  109. package/src/app/component/message/carousel/carousel.component.scss +20 -8
  110. package/src/app/component/message/carousel/carousel.component.spec.ts +80 -3
  111. package/src/app/component/message/carousel/carousel.component.ts +16 -0
  112. package/src/app/component/message/frame/frame.component.html +9 -4
  113. package/src/app/component/message/frame/frame.component.spec.ts +34 -15
  114. package/src/app/component/message/frame/frame.component.ts +7 -2
  115. package/src/app/component/message/html/html.component.html +1 -1
  116. package/src/app/component/message/html/html.component.scss +1 -1
  117. package/src/app/component/message/html/html.component.spec.ts +24 -7
  118. package/src/app/component/message/image/image.component.html +12 -10
  119. package/src/app/component/message/image/image.component.scss +16 -0
  120. package/src/app/component/message/image/image.component.spec.ts +101 -15
  121. package/src/app/component/message/image/image.component.ts +90 -51
  122. package/src/app/component/message/info-message/info-message.component.spec.ts +26 -14
  123. package/src/app/component/message/json-sources/json-sources.component.html +38 -0
  124. package/src/app/component/message/json-sources/json-sources.component.scss +201 -0
  125. package/src/app/component/message/json-sources/json-sources.component.ts +89 -0
  126. package/src/app/component/message/like-unlike/like-unlike.component.html +7 -9
  127. package/src/app/component/message/like-unlike/like-unlike.component.spec.ts +31 -3
  128. package/src/app/component/message/return-receipt/return-receipt.component.spec.ts +38 -17
  129. package/src/app/component/message/text/text.component.html +3 -3
  130. package/src/app/component/message/text/text.component.scss +80 -86
  131. package/src/app/component/message/text/text.component.spec.ts +106 -13
  132. package/src/app/component/message-attachment/message-attachment.component.spec.ts +134 -13
  133. package/src/app/component/selection-department/selection-department.component.html +21 -23
  134. package/src/app/component/selection-department/selection-department.component.spec.ts +159 -14
  135. package/src/app/component/selection-department/selection-department.component.ts +8 -1
  136. package/src/app/component/send-button/send-button.component.html +5 -13
  137. package/src/app/component/send-button/send-button.component.spec.ts +2 -2
  138. package/src/app/component/star-rating-widget/star-rating-widget.component.html +51 -81
  139. package/src/app/directives/tooltip.directive.spec.ts +8 -4
  140. package/src/app/modals/confirm-close/confirm-close.component.html +20 -8
  141. package/src/app/modals/confirm-close/confirm-close.component.scss +3 -0
  142. package/src/app/modals/confirm-close/confirm-close.component.spec.ts +13 -4
  143. package/src/app/modals/confirm-close/confirm-close.component.ts +8 -1
  144. package/src/app/pipe/html-entites-encode.pipe.spec.ts +35 -2
  145. package/src/app/pipe/marked.pipe.spec.ts +38 -2
  146. package/src/app/pipe/marked.pipe.ts +51 -41
  147. package/src/app/providers/app-config.service.ts +4 -2
  148. package/src/app/providers/brand.service.spec.ts +23 -2
  149. package/src/app/providers/brand.service.ts +1 -1
  150. package/src/app/providers/global-settings.service.spec.ts +1009 -14
  151. package/src/app/providers/global-settings.service.ts +82 -2
  152. package/src/app/providers/json-sources-parser.service.ts +175 -0
  153. package/src/app/providers/translator.service.ts +26 -6
  154. package/src/app/providers/tts-audio-playback-coordinator.service.spec.ts +117 -0
  155. package/src/app/providers/tts-audio-playback-coordinator.service.ts +109 -0
  156. package/src/app/providers/url-preview.service.ts +82 -0
  157. package/src/app/providers/voice/STT&TTS/openai-voice.config.ts +12 -0
  158. package/src/app/providers/voice/STT&TTS/openai-voice.provider.ts +171 -0
  159. package/src/app/providers/voice/STT&TTS/speech-provider.abstract.ts +39 -0
  160. package/src/app/providers/voice/audio.types.ts +40 -0
  161. package/src/app/providers/voice/vad.service.spec.ts +28 -0
  162. package/src/app/providers/voice/vad.service.ts +70 -0
  163. package/src/app/providers/voice/voice-streaming.service.spec.ts +23 -0
  164. package/src/app/providers/voice/voice-streaming.service.ts +702 -0
  165. package/src/app/providers/voice/voice-streaming.types.ts +112 -0
  166. package/src/app/providers/voice/voice.service.spec.ts +227 -0
  167. package/src/app/providers/voice/voice.service.ts +973 -0
  168. package/src/app/sass/_variables.scss +3 -0
  169. package/src/app/sass/animations.scss +19 -1
  170. package/src/app/shims/onnxruntime-web-wasm.ts +4 -0
  171. package/src/app/utils/globals.ts +21 -1
  172. package/src/app/utils/json-sources-utils.ts +27 -0
  173. package/src/app/utils/url-utils.ts +98 -0
  174. package/src/app/utils/utils-resources.ts +1 -1
  175. package/src/assets/i18n/en.json +106 -99
  176. package/src/assets/i18n/es.json +107 -100
  177. package/src/assets/i18n/fr.json +107 -100
  178. package/src/assets/i18n/it.json +107 -98
  179. package/src/assets/onnx/ort-wasm-simd-threaded.mjs +59 -0
  180. package/src/assets/onnx/ort-wasm-simd-threaded.wasm +0 -0
  181. package/src/assets/sounds/keyboard.mp3 +0 -0
  182. package/src/assets/twp/chatbot-panel.html +3 -1
  183. package/src/assets/twp/index-dev.html +18 -0
  184. package/src/assets/twp/tiledesk_widget_files/widget-css-override-example.css +14 -0
  185. package/src/assets/vad/silero_vad_legacy.onnx +0 -0
  186. package/src/assets/vad/vad.worklet.bundle.min.js +1 -0
  187. package/src/chat21-core/models/message.ts +2 -1
  188. package/src/chat21-core/providers/chat-manager.spec.ts +72 -0
  189. package/src/chat21-core/providers/firebase/firebase-conversation-handler.ts +3 -2
  190. package/src/chat21-core/providers/mqtt/mqtt-conversation-handler.ts +12 -0
  191. package/src/chat21-core/providers/scripts/script.service.spec.ts +12 -2
  192. package/src/chat21-core/providers/tiledesk/tiledesk-requests.service.ts +1 -1
  193. package/src/chat21-core/utils/constants.ts +4 -0
  194. package/src/chat21-core/utils/utils-message.ts +45 -6
  195. package/src/chat21-core/utils/utils.ts +5 -2
  196. package/src/widget-config-template.json +4 -1
  197. package/src/widget-config.json +4 -1
  198. package/tests/widget-form-rich.spec.ts +67 -0
  199. package/tests/widget-index-dev-settings.spec.ts +52 -0
  200. package/tests/widget-twp-iframe.spec.ts +39 -0
  201. package/tsconfig.json +5 -0
@@ -36,7 +36,10 @@
36
36
 
37
37
  --chat-footer-height: 64px;
38
38
  --chat-footer-logo-height: 30px;
39
+ --chat-footer-close-button-height: 30px;
39
40
  --chat-footer-border-radius: 16px;
41
+ --chat-footer-stream-button-height: 72px;
42
+ --chat-footer-stream-button-padding: 10px 0;
40
43
  --chat-footer-background-color: #f6f7fb;
41
44
  --chat-footer-color: #1a1a1a;
42
45
  --chat-footer-border-color-error: #aa0404;
@@ -1,4 +1,22 @@
1
- @import 'variables';
1
+ $trasp-black: rgba(0, 0, 0, 0.8);
2
+
3
+ /**
4
+ * Respect the user's reduced-motion preference (WCAG 2.3.3 Animation from Interactions).
5
+ * When `prefers-reduced-motion: reduce` is active, neutralize all CSS animations and transitions
6
+ * inside the widget so users do not experience non-essential motion.
7
+ */
8
+ @media (prefers-reduced-motion: reduce) {
9
+ chat-root *,
10
+ chat-root *::before,
11
+ chat-root *::after {
12
+ animation-duration: 0.001ms !important;
13
+ animation-iteration-count: 1 !important;
14
+ animation-delay: 0ms !important;
15
+ transition-duration: 0.001ms !important;
16
+ transition-delay: 0ms !important;
17
+ scroll-behavior: auto !important;
18
+ }
19
+ }
2
20
 
3
21
  /**
4
22
  * ----------------------------------------
@@ -0,0 +1,4 @@
1
+ export * from "onnxruntime-web";
2
+ import * as ort from "onnxruntime-web";
3
+
4
+ export default ort;
@@ -36,6 +36,14 @@ export class Globals {
36
36
  isMobile: boolean;
37
37
  isLogged: boolean;
38
38
  soundEnabled: boolean;
39
+ /** Volume for the keyboard typing-indicator sound during voice sessions. Range 0.0–1.0. */
40
+ keyboardSoundVolume: number;
41
+ /**
42
+ * Filename (local) or absolute URL (remote) for the keyboard typing-indicator sound.
43
+ * Local: bare filename resolved against `baseLocation + '/assets/sounds/'` (e.g. `'keyboard.mp3'`).
44
+ * Remote: full URL starting with `http://` or `https://`.
45
+ */
46
+ keyboardSoundFile: string;
39
47
  BUILD_VERSION: String;
40
48
  baseLocation: string;
41
49
  availableAgents: Array<UserAgent> = [];
@@ -117,6 +125,7 @@ export class Globals {
117
125
  WAITING_TIME_NOT_FOUND: string;
118
126
  CLOSED: string;
119
127
  LABEL_PREVIEW: string;
128
+ BUTTON_OPEN_CHAT: string;
120
129
 
121
130
  // ============ BEGIN: EXTERNAL PARAMETERS ==============//
122
131
  autoStart: boolean;
@@ -219,14 +228,18 @@ export class Globals {
219
228
  showEmojiFooterButton: boolean // ******* new ********
220
229
  showAttachmentFooterButton: boolean // ******* new ********
221
230
  showAudioRecorderFooterButton: boolean // ******* new ********
231
+ showAudioStreamFooterButton: boolean // ******* new ********
222
232
 
223
233
  allowedOnSpecificUrl: boolean // ******* new ********
224
234
  allowedOnSpecificUrlList: Array<string> // ******* new ********
225
235
  hasCalloutInWidgetConfig: boolean; // ******* new ********
226
236
 
227
237
  fontFamilySource: string; // ******* new ********
238
+ cssSource: string; // ******* new ********
228
239
 
229
240
  size: 'min' | 'max' | 'top'; // ******* new ********
241
+
242
+ closeChatInConversation: boolean; // ******* new ********
230
243
  constructor(
231
244
  ) { }
232
245
 
@@ -435,6 +448,8 @@ export class Globals {
435
448
  this.showAttachmentFooterButton = true;
436
449
  /** show/hide rec audio option in footer chat-detail page */
437
450
  this.showAudioRecorderFooterButton = true;
451
+ /** show/hide stream audio option in footer chat-detail page */
452
+ this.showAudioStreamFooterButton = true;
438
453
  /** enabled to set a list of pattern url able to load the widget **/
439
454
  this.allowedOnSpecificUrl = false
440
455
  /** set a list of pattern url able to load the widget */
@@ -443,7 +458,10 @@ export class Globals {
443
458
  this.hasCalloutInWidgetConfig = false;
444
459
  /** set widget size from 3 different positions: min, max, top */
445
460
  this.size = 'min';
446
-
461
+ /** remote CSS override URL (from window.tiledeskSettings.cssSource only) */
462
+ this.cssSource = '';
463
+ /** enable to close the chat in conversation */
464
+ this.closeChatInConversation = false;
447
465
  // ============ END: SET EXTERNAL PARAMETERS ==============//
448
466
 
449
467
 
@@ -462,6 +480,8 @@ export class Globals {
462
480
  this.BUILD_VERSION = 'v.' + environment.version;
463
481
 
464
482
  this.soundEnabled = true;
483
+ this.keyboardSoundVolume = 0.3;
484
+ this.keyboardSoundFile = 'keyboard.mp3';
465
485
 
466
486
  this.conversationsBadge = 0;
467
487
 
@@ -0,0 +1,27 @@
1
+ import { JsonSourceItem } from 'src/app/component/message/json-sources/json-sources.component';
2
+
3
+ export function extractUrlsFromJsonSources(sources: JsonSourceItem[] | null | undefined): string[] {
4
+ return (sources || [])
5
+ .map((s) => (s?.link || '').trim())
6
+ .filter(Boolean);
7
+ }
8
+
9
+ export function mergeJsonSourcesMissingFields(
10
+ base: JsonSourceItem[],
11
+ previews: JsonSourceItem[]
12
+ ): JsonSourceItem[] {
13
+ const byUrl = new Map(previews.map((p) => [p.link, p]));
14
+ return base.map((cur) => {
15
+ const p = cur?.link ? byUrl.get(cur.link) : undefined;
16
+ if (!p) return cur;
17
+ return {
18
+ ...cur,
19
+ title: cur.title || p.title,
20
+ description: cur.description || p.description,
21
+ image: cur.image || p.image,
22
+ favicon: cur.favicon || p.favicon,
23
+ favicon_hd: cur.favicon_hd || p.favicon_hd
24
+ };
25
+ });
26
+ }
27
+
@@ -0,0 +1,98 @@
1
+ export function extractUrlsFromText(text?: string, maxUrls = 20): string[] {
2
+ if (!text) return [];
3
+ const input = text.toString();
4
+ // Match candidates:
5
+ // - https?://...
6
+ // - www....
7
+ // - naked domains like google.it/path
8
+ // We later normalize + validate.
9
+ const candidateRegex =
10
+ /\b(?:https?:\/\/[^\s<>"'`)\]]+|www\.[^\s<>"'`)\]]+|[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+[^\s<>"'`)\]]*)/gi;
11
+ const matches = input.match(candidateRegex) || [];
12
+
13
+ const seen = new Set<string>();
14
+ const out: string[] = [];
15
+ for (const raw of matches) {
16
+ const normalized = normalizeAndValidateUrlCandidate(raw);
17
+ if (!normalized) continue;
18
+ if (seen.has(normalized)) continue;
19
+ seen.add(normalized);
20
+ out.push(normalized);
21
+ if (out.length >= maxUrls) break;
22
+ }
23
+ return out;
24
+ }
25
+
26
+ function normalizeAndValidateUrlCandidate(candidate: string): string | null {
27
+ if (!candidate) return null;
28
+ let s = candidate.trim();
29
+
30
+ // Drop surrounding punctuation/brackets commonly attached in text
31
+ s = s.replace(/^[("'<\[]+/, '').replace(/[)"'>\]]+$/, '');
32
+ // Drop trailing punctuation
33
+ s = s.replace(/[.,;:!?]+$/g, '').trim();
34
+ if (!s) return null;
35
+
36
+ // Reject emails quickly
37
+ if (s.includes('@')) return null;
38
+
39
+ // Add scheme if missing
40
+ if (/^www\./i.test(s)) {
41
+ s = `https://${s}`;
42
+ } else if (!/^https?:\/\//i.test(s)) {
43
+ s = `https://${s}`;
44
+ }
45
+
46
+ try {
47
+ const url = new URL(s);
48
+ const hostname = url.hostname.toLowerCase();
49
+
50
+ // must look like a real domain: contain a dot and a plausible TLD
51
+ if (!hostname.includes('.')) return null;
52
+ const tld = hostname.split('.').pop() || '';
53
+ if (tld.length < 2) return null;
54
+ if (!/^[a-z0-9-]+$/.test(tld)) return null;
55
+
56
+ // normalize: remove default port and trailing slash when path is '/'
57
+ url.hash = ''; // do not include fragments in "identity"
58
+ if (url.pathname === '/') url.pathname = '';
59
+ return url.toString();
60
+ } catch {
61
+ return null;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Best-effort "registrable domain" extractor.
67
+ * Examples:
68
+ * - "docs.example.com" -> "example.com"
69
+ * - "www.example.co.uk" -> "example.co.uk"
70
+ *
71
+ * This is a heuristic (no publicsuffix list) but works well for common cases.
72
+ */
73
+ export function getTopLevelDomainFromHostname(hostname: string): string {
74
+ const host = (hostname || '').trim().toLowerCase().replace(/\.+$/, '');
75
+ const parts = host.split('.').filter(Boolean);
76
+ if (parts.length <= 2) return host;
77
+
78
+ const tld = parts[parts.length - 1];
79
+ const sld = parts[parts.length - 2];
80
+
81
+ // Heuristic for common ccTLD second-level domains (co.uk, com.au, etc.)
82
+ const commonSecondLevel = new Set(['co', 'com', 'org', 'net', 'gov', 'ac', 'edu']);
83
+ const isCcTld = tld.length === 2;
84
+ if (isCcTld && commonSecondLevel.has(sld) && parts.length >= 3) {
85
+ return parts.slice(-3).join('.');
86
+ }
87
+ return parts.slice(-2).join('.');
88
+ }
89
+
90
+ export function getTopLevelDomainFromUrl(url: string): string {
91
+ try {
92
+ const hostname = new URL(url).hostname.replace(/^www\./, '');
93
+ return getTopLevelDomainFromHostname(hostname);
94
+ } catch {
95
+ return '';
96
+ }
97
+ }
98
+
@@ -7,7 +7,7 @@ export const BRAND_BASE_INFO: { [key: string] : string} ={
7
7
  FAVICON: "https://tiledesk.com/wp-content/uploads/2022/07/tiledesk_v13-300x300.png",
8
8
  META_TITLE:"Design Studio",
9
9
  LOGO_CHAT:"https://widget.tiledesk.com/v2/assets/images/tiledesk_logo_white_small.svg",
10
- POWERED_BY:"<a tabindex='-1' target='_blank' ref='https://www.tiledesk.com/?utm_source=widget'><img src='https://support-pre.tiledesk.com/dashboard/assets/img/logos/tiledesk-solo_logo_new_gray.svg'/><span>Powered by Tiledesk</span></a>",
10
+ POWERED_BY:"<a target='_blank' rel='noopener noreferrer' href='https://www.tiledesk.com/?utm_source=widget'><img src='https://support-pre.tiledesk.com/dashboard/assets/img/logos/tiledesk-solo_logo_new_gray.svg' alt=''/><span>Powered by Tiledesk</span></a>",
11
11
  }
12
12
 
13
13
  export const LOGOS_ITEMS: { [key: string] : { label: string, icon: string }} ={
@@ -1,101 +1,108 @@
1
1
  {
2
- "LABEL_PLACEHOLDER": "Type your message..",
3
- "LABEL_START_NW_CONV": "New conversation",
4
- "LABEL_WHATSAPP": "Message us",
5
- "LABEL_SELECT_TOPIC": "Select a topic",
6
- "LABEL_COMPLETE_FORM": "Complete the form to start a conversation with the next available agent.",
7
- "LABEL_FIELD_NAME": "Name",
8
- "LABEL_ERROR_FIELD_NAME": "Required field (minimum 5 characters).",
9
- "LABEL_FIELD_EMAIL": "Email",
10
- "LABEL_ERROR_FIELD_EMAIL": "Enter a valid email address.",
11
- "LABEL_ERROR_FIELD_REQUIRED":"Required field",
12
- "LABEL_WRITING": "is writing...",
13
- "LABEL_SEND_NEW_MESSAGE": "Send a new message",
14
- "AGENT_NOT_AVAILABLE": " Offline",
15
- "AGENT_AVAILABLE": " Online",
16
- "GUEST_LABEL": "Guest",
17
- "ALL_AGENTS_OFFLINE_LABEL": "All operators are offline at the moment",
18
- "LABEL_LOADING": "Loading...",
19
- "LABEL_THINKING": "thinking",
20
- "CALLOUT_TITLE_PLACEHOLDER": "🖐 Need Help?",
21
- "CALLOUT_MSG_PLACEHOLDER": "Click here and start chatting with us!",
22
- "CUSTOMER_SATISFACTION": "Customer satisfaction",
23
- "YOUR_OPINION_ON_OUR_CUSTOMER_SERVICE": "your opinion on our customer service",
24
- "DOWNLOAD_TRANSCRIPT": "Download transcript",
25
- "BACK": "Back",
26
- "CONTINUE": "Continue",
27
- "YOUR_RATING": "your rating",
28
- "WRITE_YOUR_OPINION": "Write your opinion ... (optional)",
29
- "SUBMIT": "Submit",
30
- "THANK_YOU_FOR_YOUR_EVALUATION": "Thank you for your evaluation",
31
- "YOUR_RATING_HAS_BEEN_RECEIVED": "your rating has been received",
32
- "ALERT_LEAVE_CHAT": "Do you want to leave the chat?",
33
- "YES": "Yes",
34
- "NO": "No",
35
- "BUTTON_CLOSE_TO_ICON": "Minimize chat",
36
- "BUTTON_EDIT_PROFILE": "Update profile",
37
- "RATE_CHAT": "Rate chat",
38
- "WELCOME_TITLE": "Hi, welcome to Tiledesk 👋",
39
- "WELCOME_MSG": "How can we help?",
40
- "WELCOME": "Welcome",
41
- "OPTIONS": "options",
42
- "SOUND_OFF": "Sound off",
43
- "SOUND_ON": "Sound on",
44
- "LOGOUT": "Logout",
45
- "CLOSE": "Close",
46
- "RESTART":"Restart",
47
- "PREV_CONVERSATIONS": "Your conversations",
48
- "YOU": "You",
49
- "SHOW_ALL_CONV": "show all",
50
- "START_A_CONVERSATION": "Start a conversation",
51
- "NO_CONVERSATION": "No conversation",
52
- "SEE_PREVIOUS": "see previous",
53
- "WAITING_TIME_FOUND": "The team typically replies in $reply_time",
54
- "WAITING_TIME_NOT_FOUND": "The team will reply as soon as possible",
55
- "CLOSED": "CLOSED",
56
- "CLOSE_CHAT": "Close chat",
57
- "MINIMIZE":"Minimize window",
58
- "MAXIMIZE":"Expand window",
59
- "CENTER":"Center",
60
- "CONFIRM_CLOSE_CHAT":"Are you sure you want to close this chat?",
61
-
62
- "INFO_SUPPORT_USER_ADDED_SUBJECT":"you",
63
- "INFO_SUPPORT_USER_ADDED_YOU_VERB":"have been added to ",
64
- "INFO_SUPPORT_USER_ADDED_COMPLEMENT":"joined",
65
- "INFO_SUPPORT_USER_ADDED_VERB":"the chat",
66
- "INFO_SUPPORT_CHAT_REOPENED":"Chat reopened",
67
- "INFO_SUPPORT_CHAT_CLOSED":"Chat closed",
68
- "INFO_SUPPORT_LEAD_UPDATED":"Lead updated",
69
- "INFO_SUPPORT_MEMBER_LEFT_GROUP":"removed from group",
70
- "INFO_SUPPORT_MEMBER_ABANDONED_GROUP":"has left the conversation",
71
- "INFO_A_NEW_SUPPORT_REQUEST_HAS_BEEN_ASSIGNED_TO_YOU": "A new support request has been assigned to you",
72
-
73
- "LABEL_PRECHAT_USER_FULLNAME": "Full name",
74
- "LABEL_PRECHAT_USER_EMAIL": "Email",
75
- "LABEL_PRECHAT_USER_EMAIL_ERROR": "Invalid email address",
76
- "LABEL_PRECHAT_USER_PHONE": "Phone",
77
- "LABEL_PRECHAT_USER_PHONE_ERROR": "Phone is required",
78
- "LABEL_PRECHAT_FIRST_MESSAGE": "Your message for the support team",
79
- "LABEL_PRECHAT_STATIC_TERMS_PRIVACY": "Before proceeding in the conversation please agree to our <a href='https://tiledesk.com/termsofservice/' target='_blank'>Terms</a> and <a href='https://tiledesk.com/privacy.html' target='_blank'>Privacy Policy</a>",
80
- "LABEL_PRECHAT_ACCEPT_TERMS_PRIVACY": "I agree",
81
- "PRECHAT_REQUIRED_ERROR": "This field is required",
82
-
83
- "TICKET_TAKING":"The request has been received and the assistance staff is dealing with it.\nTo add more comments, reply to this email.",
84
-
85
- "LABEL_TODAY": "today",
86
- "LABEL_TOMORROW": "yesterday",
87
- "LABEL_LAST_ACCESS": "last access",
88
- "LABEL_TO": "at",
89
- "ARRAY_DAYS": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
90
-
91
- "SENT_AN_ATTACHMENT": "sent an attachment",
92
- "SENT_AN_IMAGE":"sent an image",
93
-
94
- "LABEL_PREVIEW": "Preview",
95
- "SWITCH_TO": "Or switch to:",
96
- "CONNECTION_NETWORK_ERROR": "Our apologies. There was some trouble connecting to network",
97
- "EMOJI_NOT_ELLOWED":"Emoji not allowed",
98
- "DOMAIN_NOT_ALLOWED":"URL contains a non-allowed domain",
99
- "MAX_ATTACHMENT": "Max allowed size {{FILE_SIZE_LIMIT}}Mb",
100
- "EMOJI": "Emoji"
2
+ "LABEL_PLACEHOLDER": "Type your message..",
3
+ "LABEL_START_NW_CONV": "New conversation",
4
+ "LABEL_WHATSAPP": "Message us",
5
+ "LABEL_SELECT_TOPIC": "Select a topic",
6
+ "LABEL_COMPLETE_FORM": "Complete the form to start a conversation with the next available agent.",
7
+ "LABEL_FIELD_NAME": "Name",
8
+ "LABEL_ERROR_FIELD_NAME": "Required field (minimum 5 characters).",
9
+ "LABEL_FIELD_EMAIL": "Email",
10
+ "LABEL_ERROR_FIELD_EMAIL": "Enter a valid email address.",
11
+ "LABEL_ERROR_FIELD_REQUIRED": "Required field",
12
+ "LABEL_WRITING": "is writing...",
13
+ "LABEL_SEND_NEW_MESSAGE": "Send a new message",
14
+ "AGENT_NOT_AVAILABLE": " Offline",
15
+ "AGENT_AVAILABLE": " Online",
16
+ "GUEST_LABEL": "Guest",
17
+ "ALL_AGENTS_OFFLINE_LABEL": "All operators are offline at the moment",
18
+ "LABEL_LOADING": "Loading...",
19
+ "LABEL_THINKING": "thinking",
20
+ "CALLOUT_TITLE_PLACEHOLDER": "🖐 Need Help?",
21
+ "CALLOUT_MSG_PLACEHOLDER": "Click here and start chatting with us!",
22
+ "CUSTOMER_SATISFACTION": "Customer satisfaction",
23
+ "YOUR_OPINION_ON_OUR_CUSTOMER_SERVICE": "your opinion on our customer service",
24
+ "DOWNLOAD_TRANSCRIPT": "Download transcript",
25
+ "BACK": "Back",
26
+ "CONTINUE": "Continue",
27
+ "YOUR_RATING": "your rating",
28
+ "WRITE_YOUR_OPINION": "Write your opinion ... (optional)",
29
+ "SUBMIT": "Submit",
30
+ "THANK_YOU_FOR_YOUR_EVALUATION": "Thank you for your evaluation",
31
+ "YOUR_RATING_HAS_BEEN_RECEIVED": "your rating has been received",
32
+ "ALERT_LEAVE_CHAT": "Do you want to leave the chat?",
33
+ "YES": "Yes",
34
+ "NO": "No",
35
+ "BUTTON_CLOSE_TO_ICON": "Minimize chat",
36
+ "BUTTON_EDIT_PROFILE": "Update profile",
37
+ "RATE_CHAT": "Rate chat",
38
+ "WELCOME_TITLE": "Hi, welcome to Tiledesk 👋",
39
+ "WELCOME_MSG": "How can we help?",
40
+ "WELCOME": "Welcome",
41
+ "OPTIONS": "options",
42
+ "SOUND_OFF": "Sound off",
43
+ "SOUND_ON": "Sound on",
44
+ "LOGOUT": "Logout",
45
+ "CLOSE": "Close",
46
+ "RESTART": "Restart",
47
+ "PREV_CONVERSATIONS": "Your conversations",
48
+ "YOU": "You",
49
+ "SHOW_ALL_CONV": "show all",
50
+ "START_A_CONVERSATION": "Start a conversation",
51
+ "NO_CONVERSATION": "No conversation",
52
+ "SEE_PREVIOUS": "see previous",
53
+ "WAITING_TIME_FOUND": "The team typically replies in $reply_time",
54
+ "WAITING_TIME_NOT_FOUND": "The team will reply as soon as possible",
55
+ "CLOSED": "CLOSED",
56
+ "CLOSE_CHAT": "Close chat",
57
+ "MINIMIZE": "Minimize window",
58
+ "MAXIMIZE": "Expand window",
59
+ "CENTER": "Center",
60
+ "CONFIRM_CLOSE_CHAT": "Are you sure you want to close this chat?",
61
+ "INFO_SUPPORT_USER_ADDED_SUBJECT": "you",
62
+ "INFO_SUPPORT_USER_ADDED_YOU_VERB": "have been added to ",
63
+ "INFO_SUPPORT_USER_ADDED_COMPLEMENT": "joined",
64
+ "INFO_SUPPORT_USER_ADDED_VERB": "the chat",
65
+ "INFO_SUPPORT_CHAT_REOPENED": "Chat reopened",
66
+ "INFO_SUPPORT_CHAT_CLOSED": "Chat closed",
67
+ "INFO_SUPPORT_LEAD_UPDATED": "Lead updated",
68
+ "INFO_SUPPORT_MEMBER_LEFT_GROUP": "removed from group",
69
+ "INFO_SUPPORT_MEMBER_ABANDONED_GROUP": "has left the conversation",
70
+ "INFO_A_NEW_SUPPORT_REQUEST_HAS_BEEN_ASSIGNED_TO_YOU": "A new support request has been assigned to you",
71
+ "LABEL_PRECHAT_USER_FULLNAME": "Full name",
72
+ "LABEL_PRECHAT_USER_EMAIL": "Email",
73
+ "LABEL_PRECHAT_USER_EMAIL_ERROR": "Invalid email address",
74
+ "LABEL_PRECHAT_USER_PHONE": "Phone",
75
+ "LABEL_PRECHAT_USER_PHONE_ERROR": "Phone is required",
76
+ "LABEL_PRECHAT_FIRST_MESSAGE": "Your message for the support team",
77
+ "LABEL_PRECHAT_STATIC_TERMS_PRIVACY": "Before proceeding in the conversation please agree to our <a href='https://tiledesk.com/termsofservice/' target='_blank'>Terms</a> and <a href='https://tiledesk.com/privacy.html' target='_blank'>Privacy Policy</a>",
78
+ "LABEL_PRECHAT_ACCEPT_TERMS_PRIVACY": "I agree",
79
+ "PRECHAT_REQUIRED_ERROR": "This field is required",
80
+ "TICKET_TAKING": "The request has been received and the assistance staff is dealing with it.\nTo add more comments, reply to this email.",
81
+ "LABEL_TODAY": "today",
82
+ "LABEL_TOMORROW": "yesterday",
83
+ "LABEL_LAST_ACCESS": "last access",
84
+ "LABEL_TO": "at",
85
+ "ARRAY_DAYS": [
86
+ "Monday",
87
+ "Tuesday",
88
+ "Wednesday",
89
+ "Thursday",
90
+ "Friday",
91
+ "Saturday",
92
+ "Sunday"
93
+ ],
94
+ "SENT_AN_ATTACHMENT": "sent an attachment",
95
+ "SENT_AN_IMAGE": "sent an image",
96
+ "LABEL_PREVIEW": "Preview",
97
+ "SWITCH_TO": "Or switch to:",
98
+ "CONNECTION_NETWORK_ERROR": "Our apologies. There was some trouble connecting to network",
99
+ "EMOJI_NOT_ELLOWED": "Emoji not allowed",
100
+ "DOMAIN_NOT_ALLOWED": "URL contains a non-allowed domain",
101
+ "MAX_ATTACHMENT": "Max allowed size {{FILE_SIZE_LIMIT}}Mb",
102
+ "MAX_ATTACHMENT_ERROR": "The file exceeds the maximum allowed size",
103
+ "EMOJI": "Emoji",
104
+ "STREAM_AUDIO": "Use voice mode",
105
+ "VOICE_CONNECTING": "Connecting...",
106
+ "VOICE_LISTENING": "Listening...",
107
+ "VOICE_PROCESSING": "Processing..."
101
108
  }