shopify-chatbot-widget 1.0.8 → 1.0.10

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 (46) hide show
  1. package/.env.development +2 -0
  2. package/dist/jaweb-chatbot.css +1 -1
  3. package/dist/jaweb-chatbot.iife.js +192 -599
  4. package/home.html +1 -1
  5. package/jawebDirect.js +1 -1
  6. package/package.json +1 -1
  7. package/src/App.tsx +9 -0
  8. package/src/Chatbot/Chatbot.css +193 -113
  9. package/src/Chatbot/Chatbot.tsx +26 -19
  10. package/src/Chatbot/components/Cart/Index.tsx +10 -8
  11. package/src/Chatbot/components/ChatInput.tsx +11 -11
  12. package/src/Chatbot/components/Home/Home.css +456 -0
  13. package/src/Chatbot/components/Home/Home.tsx +293 -0
  14. package/src/Chatbot/components/Messages/Addcart.tsx +1 -1
  15. package/src/Chatbot/components/Messages/AssistantMesage.tsx +78 -37
  16. package/src/Chatbot/components/Messages/CardSwiper.tsx +1 -1
  17. package/src/Chatbot/components/Messages/Carousel/CardSwiper.tsx +87 -92
  18. package/src/Chatbot/components/Messages/Carousel/ProductSwiper.css +361 -0
  19. package/src/Chatbot/components/Messages/Carousel/TryOn.tsx +2 -2
  20. package/src/Chatbot/components/Messages/ChatMessages.css +32 -1
  21. package/src/Chatbot/components/Messages/ChatMessages.tsx +21 -38
  22. package/src/Chatbot/components/Messages/OrderCard.css +177 -0
  23. package/src/Chatbot/components/Messages/OrderCard.tsx +120 -0
  24. package/src/Chatbot/components/Messages/ProductCard.css +1 -1
  25. package/src/Chatbot/components/Messages/Support.tsx +311 -118
  26. package/src/Chatbot/components/Messages/Typing.css +31 -35
  27. package/src/Chatbot/components/Messages/Typing.tsx +19 -18
  28. package/src/Chatbot/components/Messenger/Messenger.tsx +67 -14
  29. package/src/Chatbot/components/Powered.css +26 -28
  30. package/src/Chatbot/components/Powered.tsx +1 -1
  31. package/src/Chatbot/components/Sessions/CreateSession.tsx +12 -10
  32. package/src/Chatbot/components/TryOn/View.tsx +2 -2
  33. package/src/Chatbot/components/VoiceMode.css +247 -0
  34. package/src/Chatbot/components/VoiceMode.tsx +613 -0
  35. package/src/hooks/config.tsx +9 -10
  36. package/src/hooks/useChatbotAPI.tsx +146 -61
  37. package/src/hooks/useChatbotData.tsx +8 -5
  38. package/src/hooks/useSessionMessages.tsx +0 -1
  39. package/src/hooks/useWebsocke.tsx +40 -18
  40. package/src/i18n.tsx +384 -10
  41. package/src/Chatbot/components/Messages/Carousel/CardSwiperSalla.tsx +0 -187
  42. package/src/Chatbot/components/Messages/Carousel/CardSwiperZid.tsx +0 -208
  43. package/src/Chatbot/components/Messages/Carousel/SallaSwiper.css +0 -245
  44. package/src/Chatbot/components/Messages/SallaAssistantMessage.tsx +0 -202
  45. package/src/Chatbot/components/Messages/ZidAssistantMesage.tsx +0 -203
  46. package/src/Chatbot/components/Sessions/RenderList.tsx +0 -519
@@ -1,6 +1,6 @@
1
1
  import { useState, useRef, useEffect } from "react";
2
2
  import type { ChangeEvent } from "react";
3
- // import { useTranslation } from "react-i18next";
3
+ import { useTranslation } from "react-i18next";
4
4
  import { message as antMessage } from "antd";
5
5
  import {
6
6
  PictureOutlined,
@@ -42,7 +42,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
42
42
  isSending,
43
43
  colorCode,
44
44
  }) => {
45
- // const { t } = useTranslation();
45
+ const { t } = useTranslation();
46
46
  const [isRecording, setIsRecording] = useState(false);
47
47
  const [isPlaying, setIsPlaying] = useState(false);
48
48
  const [recordingDuration, setRecordingDuration] = useState(0);
@@ -87,7 +87,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
87
87
  const validateImage = (file: File): boolean => {
88
88
  const maxSize = 5 * 1024 * 1024; // 5MB
89
89
  if (file.size > maxSize) {
90
- antMessage.warning("Image size should be less than 5MB");
90
+ antMessage.warning(t("input.imageTooBig"));
91
91
  return false;
92
92
  }
93
93
  return true;
@@ -143,7 +143,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
143
143
 
144
144
  const handleVoiceRecord = async () => {
145
145
  if (!navigator.mediaDevices?.getUserMedia) {
146
- antMessage.error("Voice recording is not supported in your browser");
146
+ antMessage.error(t("input.recordingUnsupported"));
147
147
  return;
148
148
  }
149
149
 
@@ -183,7 +183,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
183
183
  setIsRecording(true);
184
184
  } catch (err) {
185
185
  console.error(err);
186
- antMessage.error("Microphone permission denied");
186
+ antMessage.error(t("input.micDenied"));
187
187
  }
188
188
  } else {
189
189
  mediaRecorderRef.current?.stop();
@@ -316,7 +316,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
316
316
  <button
317
317
  className="audio-cancel-button"
318
318
  onClick={handleCancelRecording}
319
- aria-label="Cancel recording"
319
+ aria-label={t("input.cancelRecording")}
320
320
  >
321
321
  <CloseCircleOutlined />
322
322
  </button>
@@ -338,7 +338,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
338
338
  ref={textareaRef}
339
339
  value={userMessage}
340
340
  onChange={handleTextareaChange}
341
- placeholder="Enter Message ..."
341
+ placeholder={t("input.placeholder")}
342
342
  className="text-input"
343
343
  disabled={isSending}
344
344
  rows={1}
@@ -386,7 +386,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
386
386
  className="action-icon-button"
387
387
  onClick={() => fileInputRef.current?.click()}
388
388
  disabled={isSending || isRecording}
389
- aria-label="Upload image"
389
+ aria-label={t("input.uploadImage")}
390
390
  >
391
391
  <PictureOutlined />
392
392
  </button>
@@ -395,7 +395,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
395
395
  onClick={handleVoiceRecord}
396
396
  className={`action-icon-button ${isRecording ? "recording" : ""}`}
397
397
  disabled={isSending}
398
- aria-label={isRecording ? "Stop recording" : "Record voice"}
398
+ aria-label={isRecording ? t("input.stopRecording") : t("input.recordVoice")}
399
399
  >
400
400
  {isRecording ? <StopOutlined /> : <AudioOutlined />}
401
401
  </button>
@@ -428,7 +428,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
428
428
  }
429
429
  }}
430
430
  className={`send-button ${hasContent && !isSending ? "active" : ""}`}
431
- aria-label="Send message"
431
+ aria-label={t("input.sendMessage")}
432
432
  >
433
433
  {isSending ? (
434
434
  <LoadingOutlined className="send-icon spin" />
@@ -442,7 +442,7 @@ const ChatInput: React.FC<ChatInputProps> = ({
442
442
  {isDragging && (
443
443
  <div className="drag-overlay">
444
444
  <PictureOutlined className="drag-icon" />
445
- <span>Drop image here</span>
445
+ <span>{t("input.dropImage")}</span>
446
446
  </div>
447
447
  )}
448
448
  </div>
@@ -0,0 +1,456 @@
1
+ /* Widget home — the widget's landing view. All conversations, channel
2
+ choice and tickets live here. */
3
+ .jwbH {
4
+ --jwbH-accent: #111111;
5
+ height: 100%;
6
+ display: flex;
7
+ flex-direction: column;
8
+ background: #fafafa;
9
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
10
+ overflow-y: auto;
11
+ scrollbar-width: none;
12
+ }
13
+
14
+ .jwbH::-webkit-scrollbar {
15
+ display: none;
16
+ }
17
+
18
+ /* ===== Hero ===== */
19
+ .jwbH-hero {
20
+ position: relative;
21
+ background: linear-gradient(
22
+ 155deg,
23
+ var(--jwbH-accent) 0%,
24
+ color-mix(in srgb, var(--jwbH-accent) 78%, #6b7280) 100%
25
+ );
26
+ color: #ffffff;
27
+ padding: 22px 20px 40px;
28
+ flex-shrink: 0;
29
+ overflow: hidden;
30
+ }
31
+
32
+ /* soft light bloom in the corner — subtle depth, not a Tidio copy */
33
+ .jwbH-heroGlow {
34
+ position: absolute;
35
+ top: -70px;
36
+ right: -60px;
37
+ width: 220px;
38
+ height: 220px;
39
+ border-radius: 50%;
40
+ background: radial-gradient(circle, rgba(255, 255, 255, 0.16), transparent 70%);
41
+ pointer-events: none;
42
+ }
43
+
44
+ .jwbH-close {
45
+ width: 30px;
46
+ height: 30px;
47
+ border-radius: 50%;
48
+ border: none;
49
+ background: rgba(255, 255, 255, 0.14);
50
+ color: #ffffff;
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ cursor: pointer;
55
+ transition: background 0.15s ease;
56
+ z-index: 1;
57
+ }
58
+
59
+ .jwbH-close:hover {
60
+ background: rgba(255, 255, 255, 0.28);
61
+ }
62
+
63
+ .jwbH-heroTop {
64
+ display: flex;
65
+ align-items: flex-start;
66
+ justify-content: space-between;
67
+ gap: 10px;
68
+ margin-bottom: 16px;
69
+ }
70
+
71
+ .jwbH-heroCtrls {
72
+ display: inline-flex;
73
+ align-items: center;
74
+ gap: 8px;
75
+ flex-shrink: 0;
76
+ }
77
+
78
+ .jwbH-logo {
79
+ width: 42px;
80
+ height: 42px;
81
+ border-radius: 13px;
82
+ object-fit: cover;
83
+ background: #ffffff;
84
+ }
85
+
86
+ .jwbH-logoFallback {
87
+ width: 42px;
88
+ height: 42px;
89
+ border-radius: 13px;
90
+ background: rgba(255, 255, 255, 0.18);
91
+ color: #ffffff;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ font-size: 17px;
96
+ font-weight: 700;
97
+ }
98
+
99
+ .jwbH-logoWrap {
100
+ position: relative;
101
+ display: inline-flex;
102
+ }
103
+
104
+ /* online status lives on the logo — no pill */
105
+ .jwbH-logoDot {
106
+ position: absolute;
107
+ right: -3px;
108
+ bottom: -3px;
109
+ width: 11px;
110
+ height: 11px;
111
+ border-radius: 50%;
112
+ background: #4ade80;
113
+ border: 2.5px solid color-mix(in srgb, var(--jwbH-accent) 85%, #6b7280);
114
+ }
115
+
116
+ .jwbH-greeting {
117
+ margin: 0 0 4px;
118
+ font-size: 24px;
119
+ font-weight: 800;
120
+ letter-spacing: -0.03em;
121
+ }
122
+
123
+ .jwbH-greetAccent {
124
+ opacity: 0.5;
125
+ }
126
+
127
+ .jwbH-sub {
128
+ margin: 0 0 18px;
129
+ font-size: 13px;
130
+ line-height: 1.5;
131
+ opacity: 0.8;
132
+ max-width: 300px;
133
+ }
134
+
135
+ /* Channel choice */
136
+ .jwbH-channels {
137
+ display: flex;
138
+ gap: 8px;
139
+ }
140
+
141
+ .jwbH-channel {
142
+ display: inline-flex;
143
+ align-items: center;
144
+ justify-content: center;
145
+ gap: 7px;
146
+ height: 40px;
147
+ padding: 0 16px;
148
+ border-radius: 12px;
149
+ font-size: 13px;
150
+ font-weight: 700;
151
+ cursor: pointer;
152
+ text-decoration: none;
153
+ transition: transform 0.12s ease, background 0.15s ease;
154
+ border: none;
155
+ }
156
+
157
+ .jwbH-channel:active {
158
+ transform: scale(0.97);
159
+ }
160
+
161
+ .jwbH-channel--primary {
162
+ flex: 1;
163
+ background: #ffffff;
164
+ color: #111827;
165
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
166
+ }
167
+
168
+ .jwbH-channel--primary:hover {
169
+ background: #f3f4f6;
170
+ }
171
+
172
+ .jwbH-channel--whatsapp {
173
+ background: rgba(255, 255, 255, 0.14);
174
+ color: #ffffff;
175
+ border: 1px solid rgba(255, 255, 255, 0.25);
176
+ }
177
+
178
+ .jwbH-channel--whatsapp:hover {
179
+ background: rgba(255, 255, 255, 0.24);
180
+ }
181
+
182
+ /* ===== Body ===== */
183
+ .jwbH-body {
184
+ flex: 1;
185
+ padding: 0 14px 20px;
186
+ margin-top: -18px; /* cards ride up over the hero edge */
187
+ display: flex;
188
+ flex-direction: column;
189
+ gap: 12px;
190
+ position: relative;
191
+ z-index: 1;
192
+ }
193
+
194
+ .jwbH-section {
195
+ background: #ffffff;
196
+ border: 1px solid #ececec;
197
+ border-radius: 16px;
198
+ padding: 6px;
199
+ box-shadow: 0 10px 30px rgba(17, 24, 39, 0.08);
200
+ }
201
+
202
+ .jwbH-sectionHead {
203
+ display: flex;
204
+ align-items: center;
205
+ justify-content: space-between;
206
+ padding: 10px 10px 6px;
207
+ }
208
+
209
+ .jwbH-sectionHead h3 {
210
+ margin: 0;
211
+ font-size: 11px;
212
+ font-weight: 700;
213
+ letter-spacing: 0.08em;
214
+ text-transform: uppercase;
215
+ color: #9ca3af;
216
+ }
217
+
218
+ .jwbH-newBtn {
219
+ display: inline-flex;
220
+ align-items: center;
221
+ gap: 4px;
222
+ border: 1px solid #ececec;
223
+ background: #ffffff;
224
+ font-size: 11px;
225
+ font-weight: 700;
226
+ color: #111827;
227
+ cursor: pointer;
228
+ padding: 4px 10px;
229
+ border-radius: 999px;
230
+ transition: all 0.15s ease;
231
+ }
232
+
233
+ .jwbH-newBtn:hover {
234
+ border-color: #d1d5db;
235
+ background: #fafafa;
236
+ }
237
+
238
+ /* Row containers scroll internally instead of stretching the page.
239
+ Caps are exact multiples of the row height so the cutoff never slices
240
+ through a row; snap keeps scrolling resting on whole rows. */
241
+ .jwbH-rows {
242
+ overflow-y: auto;
243
+ scrollbar-width: thin;
244
+ scrollbar-color: #e5e7eb transparent;
245
+ scroll-snap-type: y proximity;
246
+ }
247
+
248
+ .jwbH-rows::-webkit-scrollbar {
249
+ width: 4px;
250
+ }
251
+
252
+ .jwbH-rows::-webkit-scrollbar-thumb {
253
+ background: #e5e7eb;
254
+ border-radius: 4px;
255
+ }
256
+
257
+ .jwbH-rows--expanded {
258
+ max-height: 260px; /* 5 rows */
259
+ }
260
+
261
+ .jwbH-rows--tickets {
262
+ max-height: 156px; /* 3 rows */
263
+ }
264
+
265
+ .jwbH-row {
266
+ display: flex;
267
+ align-items: center;
268
+ gap: 10px;
269
+ width: 100%;
270
+ height: 52px;
271
+ box-sizing: border-box;
272
+ scroll-snap-align: start;
273
+ background: none;
274
+ border: none;
275
+ border-radius: 12px;
276
+ padding: 9px 10px;
277
+ cursor: pointer;
278
+ text-align: left;
279
+ transition: background 0.12s ease;
280
+ }
281
+
282
+ .jwbH-row:hover {
283
+ background: #fafafa;
284
+ }
285
+
286
+ .jwbH-row--static {
287
+ cursor: default;
288
+ }
289
+
290
+ .jwbH-row--ended {
291
+ cursor: default;
292
+ opacity: 0.55;
293
+ }
294
+
295
+ .jwbH-rowAvatar {
296
+ width: 30px;
297
+ height: 30px;
298
+ border-radius: 9px;
299
+ object-fit: cover;
300
+ flex-shrink: 0;
301
+ border: 1px solid #ececec;
302
+ }
303
+
304
+ .jwbH-rowIcon {
305
+ width: 30px;
306
+ height: 30px;
307
+ border-radius: 9px;
308
+ background: color-mix(in srgb, var(--jwbH-accent) 8%, #ffffff);
309
+ color: var(--jwbH-accent);
310
+ display: flex;
311
+ align-items: center;
312
+ justify-content: center;
313
+ flex-shrink: 0;
314
+ }
315
+
316
+ .jwbH-rowText {
317
+ flex: 1;
318
+ display: flex;
319
+ flex-direction: column;
320
+ gap: 2px;
321
+ min-width: 0;
322
+ }
323
+
324
+ .jwbH-rowTop {
325
+ display: flex;
326
+ align-items: baseline;
327
+ justify-content: space-between;
328
+ gap: 8px;
329
+ }
330
+
331
+ .jwbH-rowTitle {
332
+ font-size: 13px;
333
+ font-weight: 600;
334
+ color: #111827;
335
+ white-space: nowrap;
336
+ overflow: hidden;
337
+ text-overflow: ellipsis;
338
+ }
339
+
340
+ .jwbH-rowTime {
341
+ font-size: 10.5px;
342
+ color: #c4c8cf;
343
+ flex-shrink: 0;
344
+ font-variant-numeric: tabular-nums;
345
+ }
346
+
347
+ .jwbH-rowSub {
348
+ font-size: 12px;
349
+ color: #6b7280;
350
+ white-space: nowrap;
351
+ overflow: hidden;
352
+ text-overflow: ellipsis;
353
+ }
354
+
355
+ .jwbH-more {
356
+ width: 100%;
357
+ border: none;
358
+ background: none;
359
+ padding: 9px 10px 7px;
360
+ font-size: 12px;
361
+ font-weight: 700;
362
+ color: #6b7280;
363
+ cursor: pointer;
364
+ border-top: 1px solid #f3f4f6;
365
+ margin-top: 2px;
366
+ transition: color 0.15s ease;
367
+ }
368
+
369
+ .jwbH-more:hover {
370
+ color: #111827;
371
+ }
372
+
373
+ .jwbH-rowArrow {
374
+ color: #d1d5db;
375
+ flex-shrink: 0;
376
+ }
377
+
378
+ .jwbH-rowSub--unread {
379
+ color: var(--jwbH-accent);
380
+ font-weight: 700;
381
+ }
382
+
383
+ .jwbH-unread {
384
+ min-width: 20px;
385
+ height: 20px;
386
+ padding: 0 6px;
387
+ border-radius: 999px;
388
+ background: var(--jwbH-accent);
389
+ color: #ffffff;
390
+ font-size: 11px;
391
+ font-weight: 700;
392
+ display: flex;
393
+ align-items: center;
394
+ justify-content: center;
395
+ flex-shrink: 0;
396
+ }
397
+
398
+ .jwbH-endedTag {
399
+ font-size: 10px;
400
+ font-weight: 700;
401
+ letter-spacing: 0.05em;
402
+ text-transform: uppercase;
403
+ color: #9ca3af;
404
+ border: 1px solid #ececec;
405
+ padding: 3px 8px;
406
+ border-radius: 999px;
407
+ flex-shrink: 0;
408
+ }
409
+
410
+ .jwbH-status {
411
+ font-size: 11px;
412
+ font-weight: 700;
413
+ padding: 4px 9px;
414
+ border-radius: 999px;
415
+ background: var(--jwbH-accent);
416
+ color: #ffffff;
417
+ flex-shrink: 0;
418
+ }
419
+
420
+ .jwbH-status--solved {
421
+ background: #16a34a;
422
+ }
423
+
424
+
425
+ /* ---- Language pill (top corner opposite the close button) ---- */
426
+ .jwbH-lang {
427
+ display: inline-flex;
428
+ align-items: center;
429
+ height: 30px;
430
+ box-sizing: border-box;
431
+ gap: 2px;
432
+ padding: 3px;
433
+ border-radius: 999px;
434
+ background: rgba(255, 255, 255, 0.16);
435
+ backdrop-filter: blur(8px);
436
+ -webkit-backdrop-filter: blur(8px);
437
+ z-index: 3;
438
+ }
439
+ .jwbH-langBtn {
440
+ border: none;
441
+ background: transparent;
442
+ color: rgba(255, 255, 255, 0.7);
443
+ font-size: 10px;
444
+ font-weight: 800;
445
+ letter-spacing: 0.04em;
446
+ padding: 4px 8px;
447
+ border-radius: 999px;
448
+ cursor: pointer;
449
+ line-height: 1;
450
+ transition: background 0.15s ease, color 0.15s ease;
451
+ }
452
+ .jwbH-langBtn:hover { color: #ffffff; }
453
+ .jwbH-langBtn--active {
454
+ background: #ffffff;
455
+ color: var(--jwbH-accent, #111111);
456
+ }