@modochats/widget 0.1.0 → 0.1.2

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 (106) hide show
  1. package/dist/src/models/conversation.js +1 -1
  2. package/dist/src/types/app.js +1 -0
  3. package/package.json +1 -1
  4. package/.vscode/settings.json +0 -3
  5. package/.yarn/install-state.gz +0 -0
  6. package/cdn-dist/README.md +0 -42
  7. package/cdn-dist/modo-web-component.js +0 -1344
  8. package/cdn-dist/modo-web-component.min.js +0 -1
  9. package/cdn-dist/package.json +0 -27
  10. package/dist/types/src/app.d.ts +0 -30
  11. package/dist/types/src/app.d.ts.map +0 -1
  12. package/dist/types/src/constants/index.d.ts +0 -10
  13. package/dist/types/src/constants/index.d.ts.map +0 -1
  14. package/dist/types/src/constants/regex.d.ts +0 -3
  15. package/dist/types/src/constants/regex.d.ts.map +0 -1
  16. package/dist/types/src/index.d.ts +0 -10
  17. package/dist/types/src/index.d.ts.map +0 -1
  18. package/dist/types/src/models/chatbot.d.ts +0 -24
  19. package/dist/types/src/models/chatbot.d.ts.map +0 -1
  20. package/dist/types/src/models/conversation.d.ts +0 -23
  21. package/dist/types/src/models/conversation.d.ts.map +0 -1
  22. package/dist/types/src/models/customer-data.d.ts +0 -32
  23. package/dist/types/src/models/customer-data.d.ts.map +0 -1
  24. package/dist/types/src/models/message-utils.d.ts +0 -13
  25. package/dist/types/src/models/message-utils.d.ts.map +0 -1
  26. package/dist/types/src/services/chat/conversation.d.ts +0 -23
  27. package/dist/types/src/services/chat/conversation.d.ts.map +0 -1
  28. package/dist/types/src/services/chat/message-utils.d.ts +0 -13
  29. package/dist/types/src/services/chat/message-utils.d.ts.map +0 -1
  30. package/dist/types/src/services/chat/model.d.ts +0 -28
  31. package/dist/types/src/services/chat/model.d.ts.map +0 -1
  32. package/dist/types/src/services/chatbot/chatbot.d.ts +0 -24
  33. package/dist/types/src/services/chatbot/chatbot.d.ts.map +0 -1
  34. package/dist/types/src/services/checker.d.ts +0 -4
  35. package/dist/types/src/services/checker.d.ts.map +0 -1
  36. package/dist/types/src/services/listeners/adders.d.ts +0 -4
  37. package/dist/types/src/services/listeners/adders.d.ts.map +0 -1
  38. package/dist/types/src/services/listeners/fn.d.ts +0 -4
  39. package/dist/types/src/services/listeners/fn.d.ts.map +0 -1
  40. package/dist/types/src/services/socket/utils.d.ts +0 -3
  41. package/dist/types/src/services/socket/utils.d.ts.map +0 -1
  42. package/dist/types/src/services/ui/fn.d.ts +0 -14
  43. package/dist/types/src/services/ui/fn.d.ts.map +0 -1
  44. package/dist/types/src/services/ui/html.d.ts +0 -4
  45. package/dist/types/src/services/ui/html.d.ts.map +0 -1
  46. package/dist/types/src/services/user/customer-data.d.ts +0 -32
  47. package/dist/types/src/services/user/customer-data.d.ts.map +0 -1
  48. package/dist/types/src/services/voice-chat/model.d.ts +0 -13
  49. package/dist/types/src/services/voice-chat/model.d.ts.map +0 -1
  50. package/dist/types/src/services/voice-chat/utils.d.ts +0 -10
  51. package/dist/types/src/services/voice-chat/utils.d.ts.map +0 -1
  52. package/dist/types/src/tools/fetch.d.ts +0 -3
  53. package/dist/types/src/tools/fetch.d.ts.map +0 -1
  54. package/dist/types/src/types/app.d.ts +0 -18
  55. package/dist/types/src/types/app.d.ts.map +0 -1
  56. package/dist/types/src/types/conversation.d.ts +0 -15
  57. package/dist/types/src/types/conversation.d.ts.map +0 -1
  58. package/dist/types/src/types/socket.d.ts +0 -7
  59. package/dist/types/src/types/socket.d.ts.map +0 -1
  60. package/dist/types/src/types/window.d.ts +0 -10
  61. package/dist/types/src/types/window.d.ts.map +0 -1
  62. package/dist/types/src/utils/audio.d.ts +0 -4
  63. package/dist/types/src/utils/audio.d.ts.map +0 -1
  64. package/dist/types/src/utils/browser.d.ts +0 -3
  65. package/dist/types/src/utils/browser.d.ts.map +0 -1
  66. package/dist/types/src/utils/fetch.d.ts +0 -19
  67. package/dist/types/src/utils/fetch.d.ts.map +0 -1
  68. package/dist/types/src/utils/uuid.d.ts +0 -7
  69. package/dist/types/src/utils/uuid.d.ts.map +0 -1
  70. package/rollup.config.js +0 -18
  71. package/rollup.dev.config.js +0 -22
  72. package/scripts/create-umd-bundle.js +0 -213
  73. package/scripts/terser-minify.js +0 -112
  74. package/src/app.ts +0 -117
  75. package/src/constants/index.ts +0 -21
  76. package/src/constants/regex.ts +0 -2
  77. package/src/index.ts +0 -16
  78. package/src/services/chat/conversation.ts +0 -135
  79. package/src/services/chat/message-utils.ts +0 -221
  80. package/src/services/chat/model.ts +0 -139
  81. package/src/services/chatbot/chatbot.ts +0 -66
  82. package/src/services/checker.ts +0 -10
  83. package/src/services/listeners/adders.ts +0 -178
  84. package/src/services/listeners/fn.ts +0 -77
  85. package/src/services/socket/utils.ts +0 -9
  86. package/src/services/ui/fn.ts +0 -254
  87. package/src/services/ui/html.ts +0 -192
  88. package/src/services/user/customer-data.ts +0 -78
  89. package/src/services/voice-chat/model.ts +0 -79
  90. package/src/services/voice-chat/utils.ts +0 -137
  91. package/src/tools/fetch.ts +0 -7
  92. package/src/types/app.ts +0 -17
  93. package/src/types/conversation.ts +0 -14
  94. package/src/types/socket.ts +0 -7
  95. package/src/types/window.ts +0 -12
  96. package/src/utils/audio.ts +0 -67
  97. package/src/utils/browser.ts +0 -4
  98. package/src/utils/fetch.ts +0 -98
  99. package/src/utils/uuid.ts +0 -13
  100. package/temp/audio/new-message.mp3 +0 -0
  101. package/temp/audio/on-hold.mp3 +0 -0
  102. package/temp/audio-processor.js +0 -261
  103. package/temp/css/index.css +0 -2283
  104. package/temp/dev.html +0 -87
  105. package/temp/index.html +0 -16
  106. package/tsconfig.json +0 -119
@@ -1,9 +0,0 @@
1
- const onSocketConnectionUpdate = (connected: boolean) => {
2
- const widget = window.getMWidget?.();
3
- const connectionIndicator = widget?.container?.querySelector(".mw-connection-status");
4
-
5
- if (connectionIndicator) {
6
- connectionIndicator.className = `mw-connection-status ${connected ? "mw-connected" : "mw-disconnected"}`;
7
- }
8
- };
9
- export {onSocketConnectionUpdate};
@@ -1,254 +0,0 @@
1
- import {BASE_STORAGE_URL, isDev} from "#src/constants/index.js";
2
- import {ConversationStatus} from "#src/types/conversation.js";
3
-
4
- function switchToConversationLayout() {
5
- const widget = window.getMWidget?.();
6
- widget?.container?.querySelector(".mw-new-conversation-btn")?.classList.remove("mw-hidden");
7
- widget?.container?.querySelector(".mw-starters-con")?.classList.add("mw-hidden");
8
- }
9
- function switchToStarterLayout() {
10
- const widget = window.getMWidget?.();
11
- widget?.container?.querySelector(".mw-new-conversation-btn")?.classList.add("mw-hidden");
12
- widget?.container?.querySelector(".mw-starters-con")?.classList.remove("mw-hidden");
13
- widget?.container?.querySelector(".mw-conversation-status-icon")?.classList.add("mw-hidden");
14
- }
15
-
16
- function setConversationType(type: keyof typeof ConversationStatus) {
17
- const widget = window.getMWidget?.();
18
- widget?.container?.querySelector(".mw-conversation-status-icon")?.classList.remove("mw-hidden");
19
- const statusIcon = widget?.container?.querySelector(".mw-conversation-status-icon");
20
-
21
- if (statusIcon) {
22
- // Remove existing mode classes
23
- statusIcon.classList.remove("mw-ai-mode", "mw-human-mode");
24
-
25
- // Add appropriate mode class
26
- if (type === "AI_CHAT") {
27
- statusIcon.classList.add("mw-ai-mode");
28
- } else {
29
- statusIcon.classList.add("mw-human-mode");
30
- }
31
- }
32
- }
33
-
34
- function loadStarters() {
35
- const widget = window.getMWidget?.();
36
- const startersContainer = widget?.container?.querySelector(".mw-starters-con");
37
- const starterItemsContainer = widget?.container?.querySelector(".mw-starter-items");
38
-
39
- startersContainer?.classList.remove("mw-hidden");
40
-
41
- for (const starter of widget?.chatbot?.starters || []) {
42
- const starterElement = document.createElement("div");
43
- starterElement.className = "mw-starter-item";
44
- starterElement.textContent = starter;
45
- starterElement.addEventListener("click", async () => {
46
- const inputEl = widget?.container?.querySelector(".mw-chat-input") as HTMLInputElement;
47
- const sendMsgBtnEl = widget?.container?.querySelector(".mw-send-message-btn") as HTMLButtonElement;
48
- switchToConversationLayout();
49
- if (inputEl) {
50
- inputEl.value = starter;
51
- sendMsgBtnEl.click();
52
- }
53
- });
54
- starterItemsContainer?.appendChild(starterElement);
55
- }
56
- }
57
-
58
- function updateChatToggleImage() {
59
- const widget = window.getMWidget?.();
60
- const toggleImageEl = widget?.container?.querySelector(".mw-chat-toggle-image") as HTMLImageElement;
61
- const starterLogoEl = widget?.container?.querySelector(".mw-starter-logo") as HTMLImageElement;
62
-
63
- const defaultSvg =
64
- "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M12 2C13.1 2 14 2.9 14 4C14 5.1 13.1 6 12 6C10.9 6 10 5.1 10 4C10 2.9 10.9 2 12 2ZM21 9V7L15 1H5C3.89 1 3 1.89 3 3V21C3 22.1 3.9 23 5 23H11V21H5V3H13V9H21ZM23 18V16H15V18L19 22L15 26V28H23V26H19L23 22L19 18H23Z'/%3E%3C/svg%3E";
65
-
66
- // Update toggle button image
67
- if (toggleImageEl) {
68
- if (widget?.chatbot?.image) {
69
- toggleImageEl.src = widget.chatbot.image;
70
- toggleImageEl.alt = widget.chatbot.name || "شروع گفتگو";
71
-
72
- // Add error handling for failed image loads
73
- toggleImageEl.onerror = () => {
74
- toggleImageEl.src = defaultSvg;
75
- toggleImageEl.alt = "پشتیبانی چت";
76
- };
77
- } else {
78
- // Use default avatar if no image is provided
79
- toggleImageEl.src = defaultSvg;
80
- toggleImageEl.alt = "پشتیبانی چت";
81
- }
82
- }
83
-
84
- // Update starter logo
85
- if (starterLogoEl) {
86
- if (widget?.chatbot?.image) {
87
- starterLogoEl.src = widget.chatbot.image;
88
- starterLogoEl.alt = widget.chatbot.name || "لوگو چت بات";
89
- starterLogoEl.style.display = "block";
90
-
91
- // Add error handling for failed image loads
92
- starterLogoEl.onerror = () => {
93
- starterLogoEl.style.display = "none";
94
- };
95
- } else {
96
- // Hide logo if no image is provided
97
- starterLogoEl.style.display = "none";
98
- }
99
- }
100
- }
101
-
102
- function updateChatTitle() {
103
- const widget = window.getMWidget?.();
104
- const chatTitleEl = widget?.container?.querySelector(".mw-chat-title") as HTMLElement;
105
- const starterTitleEl = widget?.container?.querySelector(".mw-starter-title") as HTMLElement;
106
-
107
- if (chatTitleEl || starterTitleEl) {
108
- // Use options title if no chatbot name is available
109
- const displayTitle = widget?.options?.title || widget?.chatbot?.name || "Modo";
110
-
111
- if (chatTitleEl) {
112
- chatTitleEl.textContent = displayTitle;
113
- }
114
-
115
- if (starterTitleEl) {
116
- starterTitleEl.textContent = displayTitle;
117
- }
118
- }
119
- }
120
-
121
- function applyModoOptions() {
122
- const widget = window.getMWidget?.();
123
- if (!widget?.container || !widget?.options) return;
124
-
125
- const container = widget.container;
126
- const options = widget.options;
127
-
128
- // Apply position option
129
- applyPositionOption(container, options.position!);
130
-
131
- // Apply theme option
132
- applyThemeOption(container, options.theme!);
133
-
134
- // Apply primary color option
135
- applyPrimaryColorOption(container, options.primaryColor!);
136
-
137
- // Apply foreground color option
138
- applyForegroundColorOption(container, options.foregroundColor!);
139
- }
140
-
141
- function applyPositionOption(container: HTMLDivElement, position: "left" | "right") {
142
- const widget = window.getMWidget?.()?.container as HTMLElement;
143
- if (widget) {
144
- if (position === "left") {
145
- widget.style.right = "auto";
146
- widget.style.left = "32px";
147
- widget.style.direction = "ltr";
148
-
149
- // Update chat body position for left alignment
150
- const chatBody = widget.querySelector(".mw-chat-body") as HTMLElement;
151
- if (chatBody) {
152
- chatBody.style.right = "auto";
153
- chatBody.style.left = "0";
154
- }
155
- } else {
156
- // widget.style.left = "auto";
157
- // widget.style.right = "32px";
158
- // widget.style.direction = "rtl";
159
-
160
- // Update chat body position for right alignment
161
- const chatBody = widget.querySelector(".mw-chat-body") as HTMLElement;
162
- if (chatBody) {
163
- chatBody.style.left = "auto";
164
- chatBody.style.right = "0";
165
- }
166
- }
167
- }
168
- }
169
-
170
- function applyThemeOption(container: HTMLDivElement, theme: "dark" | "light") {
171
- // Set the theme attribute on the container or document
172
- const widget = document.querySelector(".modo-widget");
173
- if (theme === "light") {
174
- widget?.setAttribute("data-theme", "light");
175
- } else {
176
- widget?.removeAttribute("data-theme");
177
- }
178
-
179
- // Store theme preference
180
- localStorage.setItem("modo-component:theme", theme);
181
- }
182
-
183
- function applyPrimaryColorOption(container: HTMLDivElement, primaryColor: string) {
184
- // Create CSS custom properties for the primary color
185
- const root = document.querySelector(".modo-widget") as HTMLDivElement;
186
- if (root) {
187
- // Set the primary color
188
- root?.style.setProperty("--primary-color", primaryColor);
189
-
190
- // Generate hover color (slightly darker)
191
- const hoverColor = adjustColorBrightness(primaryColor, -20);
192
- root?.style.setProperty("--primary-hover", hoverColor);
193
-
194
- // Generate gradient using the primary color
195
- const gradientColor = adjustColorBrightness(primaryColor, 15);
196
- root?.style.setProperty("--primary-gradient", `linear-gradient(135deg, ${primaryColor} 0%, ${gradientColor} 100%)`);
197
- } else console.error("modo chat widget not found");
198
- }
199
-
200
- function applyForegroundColorOption(container: HTMLDivElement, foregroundColor: string) {
201
- // Create CSS custom properties for the foreground color
202
- const root = document.querySelector(".modo-widget") as HTMLDivElement;
203
- if (root) {
204
- // Set the foreground color
205
- root?.style.setProperty("--foreground-color", foregroundColor);
206
-
207
- // Set white color to use foreground color for white text elements
208
- root?.style.setProperty("--white", foregroundColor);
209
- } else console.error("modo chat widget not found");
210
- }
211
-
212
- function adjustColorBrightness(hex: string, percent: number): string {
213
- // Remove # if present
214
- hex = hex.replace(/^#/, "");
215
-
216
- // Parse r, g, b values
217
- const num = parseInt(hex, 16);
218
- const amt = Math.round(2.55 * percent);
219
- const R = (num >> 16) + amt;
220
- const G = ((num >> 8) & 0x00ff) + amt;
221
- const B = (num & 0x0000ff) + amt;
222
-
223
- // Ensure values stay within 0-255 range
224
- const newR = Math.max(0, Math.min(255, R));
225
- const newG = Math.max(0, Math.min(255, G));
226
- const newB = Math.max(0, Math.min(255, B));
227
-
228
- return `#${((newR << 16) | (newG << 8) | newB).toString(16).padStart(6, "0")}`;
229
- }
230
- async function loadCss() {
231
- return await new Promise(resolve => {
232
- const link = document.createElement("link");
233
- const source = isDev ? "/css/index.css" : `${BASE_STORAGE_URL}/index.css`;
234
- link.rel = "stylesheet";
235
- link.href = source;
236
- document.head.appendChild(link);
237
- link.addEventListener("load", () => {
238
- resolve("css loaded");
239
- });
240
- });
241
- }
242
- export {
243
- switchToConversationLayout,
244
- switchToStarterLayout,
245
- setConversationType,
246
- loadStarters,
247
- loadCss,
248
- updateChatToggleImage,
249
- updateChatTitle,
250
- applyModoOptions,
251
- applyPositionOption,
252
- applyThemeOption,
253
- applyPrimaryColorOption
254
- };
@@ -1,192 +0,0 @@
1
- import {Widget} from "#src/app.js";
2
- import {registerListeners} from "../listeners/adders.js";
3
-
4
- const createChatContainer = (widget: Widget) => {
5
- widget.container = document.createElement("div");
6
- widget.container.textContent = "Start Chat";
7
- widget.container.classList.add("modo-widget");
8
-
9
- // Add fullscreen class if fullscreen mode is enabled
10
- if (widget.options.fullScreen) {
11
- widget.container.classList.add("mw-fullscreen");
12
- }
13
-
14
- document.body.appendChild(widget.container);
15
- let conBody = document.createElement("div");
16
- widget.container.appendChild(conBody);
17
- widget.container.innerHTML = `
18
- <div dir="rtl" class="mw-chat-inner">
19
- <div class="mw-chat-body ${widget.options.fullScreen ? "mw-active" : "mw-hidden"}">
20
- <div class="mw-chat-container">
21
- <!-- Chat Header -->
22
- <div class="mw-chat-header">
23
- <div style="display: flex; align-items: center; gap: 8px;">
24
- <h3 class="mw-chat-title">پشتیبانی چت</h3>
25
- <div class="mw-conversation-status-icon mw-hidden">
26
- <!-- Clean AI/Bot icon -->
27
- <svg class="mw-ai-chat-icon" style="width: 14px; height: 14px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><!-- Icon from Material Design Icons by Pictogrammers - https://github.com/Templarian/MaterialDesign/blob/master/LICENSE --><path fill="currentColor" d="M22 14h-1c0-3.87-3.13-7-7-7h-1V5.73A2 2 0 1 0 10 4c0 .74.4 1.39 1 1.73V7h-1c-3.87 0-7 3.13-7 7H2c-.55 0-1 .45-1 1v3c0 .55.45 1 1 1h1v1a2 2 0 0 0 2 2h14c1.11 0 2-.89 2-2v-1h1c.55 0 1-.45 1-1v-3c0-.55-.45-1-1-1m-1 3h-2v3H5v-3H3v-1h2v-2c0-2.76 2.24-5 5-5h4c2.76 0 5 2.24 5 5v2h2zM8.5 13.5l2.36 2.36l-1.18 1.18l-1.18-1.18l-1.18 1.18l-1.18-1.18zm7 0l2.36 2.36l-1.18 1.18l-1.18-1.18l-1.18 1.18l-1.18-1.18z"/></svg>
28
- <!-- Clean Human/Person icon -->
29
- <svg class="mw-human-chat-icon" viewBox="0 0 24 24" width="18" height="18">
30
- <path fill="currentColor" d="M12 4C13.66 4 15 5.34 15 7C15 8.66 13.66 10 12 10C10.34 10 9 8.66 9 7C9 5.34 10.34 4 12 4ZM12 12C15.31 12 18 13.34 18 15V18H6V15C6 13.34 8.69 12 12 12Z"/>
31
- </svg>
32
- <div class="mw-tooltip">
33
- <span class="mw-tooltip-text-ai">چت بات هوشمند</span>
34
- <span class="mw-tooltip-text-human">پشتیبان انسانی</span>
35
- </div>
36
- </div>
37
- <div class="mw-connection-status mw-disconnected"></div>
38
- </div>
39
- <div style="display: flex; align-items: center; gap: 8px;">
40
- <button class="mw-new-conversation-btn mw-hidden">
41
- +
42
- </button>
43
- <button class="mw-voice-call-btn mw-hidden">
44
- <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Google Material Icons by Material Design Authors - https://github.com/material-icons/material-icons/blob/master/LICENSE --><path fill="currentColor" d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24c1.12.37 2.33.57 3.57.57c.55 0 1 .45 1 1V20c0 .55-.45 1-1 1c-9.39 0-17-7.61-17-17c0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1c0 1.25.2 2.45.57 3.57c.11.35.03.74-.25 1.02z"/></svg>
45
- <div class="mw-voice-call-tooltip mw-hidden">
46
- <div class="mw-voice-call-tooltip-text">مکالمه با هوش مصنوعی</div>
47
- </div>
48
- </button>
49
- </div>
50
- </div>
51
-
52
- <div class="mw-chat-messages-con">
53
- </div>
54
- <div class="mw-starters-con">
55
- <div class="mw-starter-welcome">
56
- <img class="mw-starter-logo" src="" alt="لوگو چت بات" style="display: none;">
57
- <h2 class="mw-starter-title">پشتیبانی چت</h2>
58
- </div>
59
- <div class="mw-starter-items">
60
- </div>
61
- </div>
62
-
63
- <div class="mw-reply-preview mw-hidden">
64
- <div class="mw-reply-preview-content">
65
- <div class="mw-reply-preview-info">
66
- <span class="mw-reply-preview-label">پاسخ به:</span>
67
- <span class="mw-reply-preview-text"></span>
68
- </div>
69
- <button class="mw-reply-preview-close" title="لغو پاسخ">
70
- <svg viewBox="0 0 24 24" width="16" height="16">
71
- <path fill="currentColor" d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z"/>
72
- </svg>
73
- </button>
74
- </div>
75
- </div>
76
-
77
- <div class="mw-chat-input-area">
78
- <input type="text" placeholder="پیام خود را تایپ کنید..." class="mw-chat-input">
79
- <button class="mw-file-upload-btn" title="آپلود فایل">
80
- <input type="file" class="mw-file-input" hidden />
81
- <svg class="mw-file-upload-icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols Light by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M16.346 11.385V6.769h1v4.616zm-5.538 5.457q-.452-.269-.726-.734q-.274-.466-.274-1.031V6.769h1zM11.96 21q-2.271 0-3.846-1.595t-1.575-3.867v-8.73q0-1.587 1.09-2.697Q8.722 3 10.309 3t2.678 1.11t1.091 2.698V14h-1V6.789q-.006-1.166-.802-1.977T10.308 4q-1.163 0-1.966.821q-.804.821-.804 1.987v8.73q-.005 1.853 1.283 3.157Q10.11 20 11.961 20q.556 0 1.056-.124t.945-.372v1.11q-.468.2-.972.293q-.505.093-1.03.093m4.386-1v-2.616h-2.615v-1h2.615V13.77h1v2.615h2.616v1h-2.616V20z"/></svg>
82
- <svg class="mw-file-remove-icon mw-hidden" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols Light by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M11.962 21q-2.273 0-3.848-1.594t-1.575-3.867V7.954L2.091 3.508L2.8 2.8l18.4 18.4l-.708.708l-3.805-3.806q-.664 1.298-1.913 2.098t-2.812.8M7.539 8.954v6.584q-.006 1.852 1.282 3.157T11.961 20q1.356 0 2.413-.727t1.574-1.91l-1.98-1.98q-.087.742-.656 1.295q-.568.553-1.35.553q-.881 0-1.518-.627q-.636-.627-.636-1.527v-3.854zm3.269 3.269v2.854q0 .479.328.816q.328.338.806.338q.474 0 .801-.335t.334-.808v-.596zm5.538 1.33V6.77h1v7.804zm-3.269-3.307V6.79q-.006-1.166-.805-1.977T10.308 4q-.708 0-1.281.32q-.573.319-.961.857l-.714-.713q.529-.68 1.285-1.072T10.307 3q1.587 0 2.679 1.11t1.091 2.698v4.458zm-2.27-3.477v1.189l-1-1.02V6.77z"/></svg>
83
- </button>
84
- <button class="mw-send-message-btn" data-is-loading="false">
85
- <svg class="mw-send-icon" viewBox="0 0 24 24">
86
- <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
87
- </svg>
88
- <span class="mw-btn-loading">
89
- <svg class="mw-loading-spinner" viewBox="0 0 24 24">
90
- <circle class="mw-spinner-circle" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle>
91
- <path class="mw-spinner-path" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
92
- </svg>
93
- </span>
94
- </button>
95
- </div>
96
-
97
- <div class="mw-form-overlay mw-hidden">
98
- <div class="mw-form-content">
99
- <h3 class="mw-form-title">اطلاعات تماس</h3>
100
- <p class="mw-form-subtitle">لطفا برای اطلاع رسانی بهتر پیام ها شماره خود را وارد کنید (اختیاری)</p>
101
- <div class="mw-form-input-area">
102
- <input type="tel" placeholder="شماره تلفن (اختیاری)" class="mw-phone-input">
103
- </div>
104
- <div class="mw-form-buttons">
105
- <button class="mw-form-submit-btn">
106
- ارسال
107
- </button>
108
- <button class="mw-form-cancel-btn">
109
- لغو
110
- </button>
111
- </div>
112
- </div>
113
- </div>
114
-
115
- <!-- Chat Footer -->
116
- <div class="mw-chat-footer">
117
- <span class="mw-footer-text">ساخته شده با </span>
118
- <a href="" class="mw-footer-link" target="_blank" rel="noopener noreferrer" title="">مودوچت</a>
119
- </div>
120
-
121
- <!-- Voice Agent Overlay -->
122
- <div class="mw-voice-agent-overlay mw-hidden">
123
- <div class="mw-voice-agent-content">
124
- <button class="mw-voice-close-btn">
125
- <svg viewBox="0 0 24 24" width="24" height="24">
126
- <path fill="currentColor" d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z"/>
127
- </svg>
128
- </button>
129
-
130
- <div class="mw-voice-agent-center">
131
- <img class="mw-voice-agent-logo" src="" alt="چت بات" />
132
- <h2 class="mw-voice-agent-title">تماس صوتی</h2>
133
- <p class="mw-voice-agent-status">درحال اتصال...</p>
134
- </div>
135
-
136
- <div class="mw-voice-agent-controls">
137
- <button class="mw-voice-disconnect-btn" title="قطع تماس">
138
- <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE --><path fill="currentColor" d="M231.59 90.13C175.44 34 80.56 34 24.41 90.13c-20 20-21.92 49.49-4.69 71.71A16 16 0 0 0 32.35 168a15.8 15.8 0 0 0 5.75-1.08l49-17.37l.29-.11a16 16 0 0 0 9.75-11.73l5.9-29.52a76.52 76.52 0 0 1 49.68-.11l6.21 29.75a16 16 0 0 0 9.72 11.59l.29.11l49 17.39a16 16 0 0 0 18.38-5.06c17.19-22.24 15.26-51.73-4.73-71.73M223.67 152l-.3-.12l-48.82-17.33l-6.21-29.74A16 16 0 0 0 158 93a92.56 92.56 0 0 0-60.34.13a16 16 0 0 0-10.32 12l-5.9 29.51l-48.81 17.22c-.1 0-.17.13-.27.17c-12.33-15.91-11-36.23 3.36-50.58c25-25 58.65-37.53 92.28-37.53s67.27 12.51 92.28 37.53c14.33 14.35 15.72 34.67 3.39 50.55m.32 48a8 8 0 0 1-8 8H40a8 8 0 0 1 0-16h176a8 8 0 0 1 8 8Z"/></svg>
139
- </button>
140
- </div>
141
- </div>
142
- </div>
143
- </div>
144
- </div>
145
- ${
146
- !widget.options.fullScreen
147
- ? `
148
- <button class="mw-toggle-chat-btn">
149
- <img
150
- class="mw-chat-toggle-image"
151
- src=""
152
- alt="شروع گفتگو" />
153
- <svg
154
- class="mw-chat-toggle-close"
155
- viewBox="0 0 24 24"
156
- width="24"
157
- height="24">
158
- <path
159
- fill="currentColor"
160
- d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z" />
161
- </svg>
162
- <!-- Badge for unread messages -->
163
- <div class="mw-badge mw-hidden">
164
- <span class="mw-badge-text">0</span>
165
- </div>
166
- <!-- Tooltip for toggle button -->
167
- <div class="mw-toggle-tooltip mw-hidden">
168
- <div class="mw-tooltip-inner">
169
- <div
170
- class="mw-toggle-tooltip-close"
171
- title="بستن">
172
- <svg
173
- viewBox="0 0 24 24"
174
- width="16"
175
- height="16">
176
- <path
177
- fill="currentColor"
178
- d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z" />
179
- </svg>
180
- </div>
181
- <span class="mw-toggle-tooltip-text">شروع گفتگو</span>
182
- </div>
183
- </div>
184
- </button>
185
- `
186
- : ""
187
- }
188
- </div>
189
- `;
190
- registerListeners(widget.container);
191
- };
192
- export {createChatContainer};
@@ -1,78 +0,0 @@
1
- import {Widget} from "#src/app.js";
2
- import {fetchUpdateUserData} from "#src/utils/fetch.js";
3
- import {generateUUID} from "#src/utils/uuid.js";
4
-
5
- class CustomerData {
6
- private _uniqueId?: string;
7
- private _userData?: Record<string, any>;
8
- private widget: Widget;
9
- phoneNumber?: string;
10
-
11
- constructor(widget: Widget, userData?: Record<string, any>) {
12
- this.widget = widget;
13
- this.initializeUniqueId();
14
- this.updateUserData(userData);
15
- this.initializePhoneNumber();
16
- }
17
-
18
- initializePhoneNumber() {
19
- const savedPhoneNumber = localStorage.getItem(`modo-chat:${this.widget.publicKey}-user-phone-number`);
20
- if (savedPhoneNumber) {
21
- this.phoneNumber = savedPhoneNumber;
22
- }
23
- }
24
-
25
- /**
26
- * Initialize unique ID from localStorage or generate a new one
27
- * Unique ID is independent of user key/data and is generated by ourselves
28
- */
29
- private initializeUniqueId(): void {
30
- const savedUniqueId = localStorage.getItem(`modo-chat:${this.widget.publicKey}-user-unique-id`);
31
-
32
- if (savedUniqueId) {
33
- this._uniqueId = savedUniqueId;
34
- } else {
35
- // Generate a new UUID if no saved unique ID exists
36
- this._uniqueId = crypto.randomUUID ? crypto.randomUUID() : generateUUID();
37
- localStorage.setItem(`modo-chat:${this.widget.publicKey}-user-unique-id`, this._uniqueId);
38
- }
39
- }
40
-
41
- /**
42
- * Get the current unique ID
43
- */
44
- get uniqueId(): string {
45
- return this._uniqueId!;
46
- }
47
-
48
- /**
49
- * Get the current user data
50
- */
51
- get userData(): Record<string, any> {
52
- return this._userData || {};
53
- }
54
-
55
- /**
56
- * Update user data with new values
57
- * @param newUserData - Object containing new user data to merge
58
- */
59
- async updateUserData(newUserData?: Record<string, any>): Promise<void> {
60
- if (newUserData && typeof newUserData === "object") {
61
- this._userData = newUserData;
62
- } else if (newUserData) console.warn("Invalid user data");
63
- }
64
-
65
- hasSubmittedPhoneForm(): boolean {
66
- return Boolean(this.phoneNumber);
67
- }
68
-
69
- savePhoneNumber(phoneNumber?: string) {
70
- this.phoneNumber = phoneNumber || "no phone number";
71
- localStorage.setItem(`modo-chat:${this.widget.publicKey}-user-phone-number`, phoneNumber || "no phone number");
72
- }
73
-
74
- async fetchUpdate() {
75
- await fetchUpdateUserData(this.widget.chatbot?.uuid as string, this.uniqueId, this.userData);
76
- }
77
- }
78
- export {CustomerData};
@@ -1,79 +0,0 @@
1
- import {VoiceClient, EventType} from "@modochats/voice-client";
2
-
3
- import {
4
- initVoiceChatLayout,
5
- handleVoiceConnected,
6
- handleVoiceDisconnected,
7
- handleVoiceConnectionError,
8
- handleMicrophonePaused,
9
- handleMicrophoneResumed
10
- } from "./utils.js";
11
-
12
- class VoiceChat {
13
- instance?: VoiceClient;
14
- isFirstInSession: boolean = true;
15
- constructor() {
16
- const widget = window.getMWidget?.();
17
- this.instance = new VoiceClient({
18
- apiBase: "https://live.modochats.com",
19
- // apiBase: "http://localhost:8000",
20
- chatbotUuid: widget?.chatbot?.uuid as string,
21
- userUniqueId: widget?.customerData.uniqueId as string
22
- });
23
- this.instance.on(EventType.CONNECTED, (event: any) => {
24
- handleVoiceConnected();
25
- });
26
-
27
- this.instance.on(EventType.DISCONNECTED, (event: any) => {
28
- if (event.reason) {
29
- }
30
- handleVoiceDisconnected(event.reason);
31
- });
32
-
33
- this.instance.on(EventType.CONNECTION_ERROR, (event: any) => {
34
- // console.error("🔴 Connection Error:", event.message);
35
- handleVoiceConnectionError(event.message);
36
- });
37
-
38
- this.instance.on(EventType.MICROPHONE_PAUSED, () => {
39
- handleMicrophonePaused();
40
- });
41
-
42
- this.instance.on(EventType.MICROPHONE_RESUMED, () => {
43
- handleMicrophoneResumed();
44
- });
45
- // Initialize the voice agent UI
46
- this.initHtml();
47
-
48
- // session check
49
- const hasSeen = sessionStorage.getItem("modochats:voice-agent-seen") === "true";
50
- if (hasSeen) this.isFirstInSession = false;
51
- else sessionStorage.setItem("modochats:voice-agent-seen", "true");
52
- if (this.isFirstInSession) this.showTooltip();
53
- }
54
- async connect() {
55
- try {
56
- await this.instance?.connect();
57
- } catch (error) {
58
- // console.error("Failed to connect:", error);
59
- }
60
- }
61
- async disconnect() {
62
- await this.instance?.disconnect();
63
- }
64
- initHtml() {
65
- initVoiceChatLayout();
66
- }
67
- toggleLayout() {
68
- this.toggleLayout();
69
- }
70
-
71
- showTooltip() {
72
- const tooltip = document.querySelector(".mw-voice-call-tooltip");
73
- tooltip?.classList.remove("mw-hidden");
74
- setTimeout(() => {
75
- tooltip?.classList.add("mw-hidden");
76
- }, 6000);
77
- }
78
- }
79
- export {VoiceChat};