@shop-prompter/react 0.1.1 → 1.1.0
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/CHANGELOG.md +12 -0
- package/dist/index.js +1433 -373
- package/dist/index.mjs +1434 -374
- package/package.json +24 -23
- package/src/api/icons.ts +9 -0
- package/src/api/product-api.ts +121 -0
- package/src/api/session-handler.ts +153 -0
- package/src/api/shop-prompter-api.ts +58 -30
- package/src/api/shop-prompter.types.ts +3 -1
- package/src/product-card-list.component.jsx +271 -0
- package/src/shop-prompter.component.jsx +922 -276
- package/src/shop-prompter.service.ts +60 -18
- package/src/thumbs-down-icon.component.jsx +25 -0
- package/src/thumbs-up-icon.component.jsx +25 -0
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { useState, useEffect } from "react";
|
|
4
|
+
import { marked } from "marked";
|
|
4
5
|
import { ShopPrompterService } from "./shop-prompter.service";
|
|
6
|
+
import ThumbsUpIcon from "./thumbs-up-icon.component";
|
|
7
|
+
import ThumbsDownIcon from "./thumbs-down-icon.component";
|
|
8
|
+
import ProductCardList from "./product-card-list.component";
|
|
9
|
+
const THINKING_SPINNER = "M21 12a9 9 0 1 1-6.219-8.56";
|
|
5
10
|
const styles = {
|
|
6
11
|
header: {
|
|
7
12
|
display: "flex",
|
|
8
13
|
alignItems: "center",
|
|
9
14
|
justifyContent: "space-between",
|
|
10
15
|
padding: "16px",
|
|
16
|
+
borderBottom: "1px solid #e5e7eb",
|
|
11
17
|
},
|
|
12
18
|
subHeaderContainer: {
|
|
13
19
|
display: "flex",
|
|
@@ -23,6 +29,7 @@ const styles = {
|
|
|
23
29
|
border: "none",
|
|
24
30
|
cursor: "pointer",
|
|
25
31
|
transition: "background-color 0.2s, color 0.2s",
|
|
32
|
+
fontFamily: "inherit",
|
|
26
33
|
onHover: {
|
|
27
34
|
backgroundColor: "hsl(220 14% 96%)",
|
|
28
35
|
color: "hsl(220 13% 13%)",
|
|
@@ -44,6 +51,7 @@ const styles = {
|
|
|
44
51
|
cursor: "pointer",
|
|
45
52
|
fontSize: "0.875rem",
|
|
46
53
|
color: "#09090b",
|
|
54
|
+
fontFamily: "inherit",
|
|
47
55
|
},
|
|
48
56
|
ButtonSheetButton: {
|
|
49
57
|
color: "#6b7280",
|
|
@@ -53,10 +61,12 @@ const styles = {
|
|
|
53
61
|
padding: "0.25rem",
|
|
54
62
|
fontSize: "1.25rem",
|
|
55
63
|
transition: "color 0.2s",
|
|
64
|
+
fontFamily: "inherit",
|
|
56
65
|
},
|
|
57
66
|
chatContainer: {
|
|
58
67
|
flex: 1,
|
|
59
68
|
overflowY: "auto",
|
|
69
|
+
overflowX: "hidden",
|
|
60
70
|
padding: "1rem",
|
|
61
71
|
backgroundColor: "white",
|
|
62
72
|
},
|
|
@@ -103,11 +113,16 @@ const styles = {
|
|
|
103
113
|
display: "flex",
|
|
104
114
|
flexDirection: "column",
|
|
105
115
|
alignItems: "flex-end",
|
|
116
|
+
marginBottom: "8px",
|
|
106
117
|
},
|
|
107
118
|
messageContainerAssistant: {
|
|
108
119
|
display: "flex",
|
|
109
120
|
flexDirection: "column",
|
|
110
121
|
alignItems: "flex-start",
|
|
122
|
+
marginBottom: "8px",
|
|
123
|
+
width: "100%",
|
|
124
|
+
maxWidth: "100%",
|
|
125
|
+
boxSizing: "border-box",
|
|
111
126
|
},
|
|
112
127
|
messageBubbleUser: {
|
|
113
128
|
backgroundColor: "#111827",
|
|
@@ -118,6 +133,7 @@ const styles = {
|
|
|
118
133
|
fontSize: "0.875rem",
|
|
119
134
|
boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
|
120
135
|
maxWidth: "85%",
|
|
136
|
+
textAlign: "left",
|
|
121
137
|
},
|
|
122
138
|
messageBubbleAssistant: {
|
|
123
139
|
backgroundColor: "#f3f4f6",
|
|
@@ -128,6 +144,7 @@ const styles = {
|
|
|
128
144
|
fontSize: "0.875rem",
|
|
129
145
|
boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
|
|
130
146
|
maxWidth: "85%",
|
|
147
|
+
textAlign: "left",
|
|
131
148
|
},
|
|
132
149
|
thinkingIndicator: {
|
|
133
150
|
display: "flex",
|
|
@@ -210,6 +227,7 @@ const styles = {
|
|
|
210
227
|
fontSize: "0.875rem",
|
|
211
228
|
color: "#111827",
|
|
212
229
|
padding: "0.25rem 0",
|
|
230
|
+
fontFamily: "inherit",
|
|
213
231
|
},
|
|
214
232
|
formButton: {
|
|
215
233
|
backgroundColor: "transparent",
|
|
@@ -223,6 +241,7 @@ const styles = {
|
|
|
223
241
|
border: "none",
|
|
224
242
|
cursor: "pointer",
|
|
225
243
|
transition: "background-color 0.2s",
|
|
244
|
+
fontFamily: "inherit",
|
|
226
245
|
},
|
|
227
246
|
sendButton: {
|
|
228
247
|
backgroundColor: "#AD59FF1A",
|
|
@@ -233,7 +252,161 @@ const styles = {
|
|
|
233
252
|
textAlign: "center",
|
|
234
253
|
marginTop: "0.75rem",
|
|
235
254
|
},
|
|
255
|
+
backdrop: {
|
|
256
|
+
position: "fixed",
|
|
257
|
+
top: 0,
|
|
258
|
+
left: 0,
|
|
259
|
+
right: 0,
|
|
260
|
+
bottom: 0,
|
|
261
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
262
|
+
backdropFilter: "blur(4px)",
|
|
263
|
+
zIndex: 1000,
|
|
264
|
+
},
|
|
265
|
+
feedbackRow: {
|
|
266
|
+
display: "flex",
|
|
267
|
+
alignItems: "center",
|
|
268
|
+
gap: "0.5rem",
|
|
269
|
+
marginTop: "0.5rem",
|
|
270
|
+
marginLeft: "0.75rem",
|
|
271
|
+
},
|
|
272
|
+
feedbackButton: {
|
|
273
|
+
backgroundColor: "transparent",
|
|
274
|
+
border: "none",
|
|
275
|
+
cursor: "pointer",
|
|
276
|
+
padding: "6px",
|
|
277
|
+
borderRadius: "6px",
|
|
278
|
+
display: "flex",
|
|
279
|
+
alignItems: "center",
|
|
280
|
+
justifyContent: "center",
|
|
281
|
+
transition: "background-color 0.2s",
|
|
282
|
+
},
|
|
283
|
+
warningBanner: {
|
|
284
|
+
backgroundColor: "#fffbeb",
|
|
285
|
+
color: "#b45309",
|
|
286
|
+
border: "1px solid #fde68a",
|
|
287
|
+
borderRadius: "0.375rem",
|
|
288
|
+
padding: "0.25rem 0.5rem",
|
|
289
|
+
fontSize: "0.6875rem",
|
|
290
|
+
fontWeight: 500,
|
|
291
|
+
textAlign: "center",
|
|
292
|
+
margin: "0 0.5rem",
|
|
293
|
+
flex: 1,
|
|
294
|
+
display: "flex",
|
|
295
|
+
alignItems: "center",
|
|
296
|
+
justifyContent: "center",
|
|
297
|
+
},
|
|
298
|
+
insufficientConfigContainer: {
|
|
299
|
+
flex: 1,
|
|
300
|
+
display: "flex",
|
|
301
|
+
flexDirection: "column",
|
|
302
|
+
alignItems: "center",
|
|
303
|
+
justifyContent: "center",
|
|
304
|
+
padding: "2rem",
|
|
305
|
+
textAlign: "center",
|
|
306
|
+
backgroundColor: "#fff5f5",
|
|
307
|
+
color: "#2d3748",
|
|
308
|
+
},
|
|
309
|
+
insufficientConfigIconContainer: {
|
|
310
|
+
backgroundColor: "#fee2e2",
|
|
311
|
+
padding: "1rem",
|
|
312
|
+
borderRadius: "50%",
|
|
313
|
+
marginBottom: "1rem",
|
|
314
|
+
display: "flex",
|
|
315
|
+
alignItems: "center",
|
|
316
|
+
justifyContent: "center",
|
|
317
|
+
boxShadow:
|
|
318
|
+
"0 4px 6px -1px rgba(239, 68, 68, 0.1), 0 2px 4px -1px rgba(239, 68, 68, 0.06)",
|
|
319
|
+
},
|
|
320
|
+
insufficientConfigTitle: {
|
|
321
|
+
fontSize: "1.25rem",
|
|
322
|
+
fontWeight: 700,
|
|
323
|
+
color: "#991b1b",
|
|
324
|
+
marginBottom: "0.5rem",
|
|
325
|
+
},
|
|
326
|
+
insufficientConfigMessage: {
|
|
327
|
+
fontSize: "0.875rem",
|
|
328
|
+
color: "#7f1d1d",
|
|
329
|
+
marginBottom: "1.5rem",
|
|
330
|
+
lineHeight: "1.5",
|
|
331
|
+
maxWidth: "280px",
|
|
332
|
+
},
|
|
333
|
+
insufficientConfigDetails: {
|
|
334
|
+
backgroundColor: "white",
|
|
335
|
+
border: "1px solid #fee2e2",
|
|
336
|
+
borderRadius: "0.5rem",
|
|
337
|
+
padding: "1rem",
|
|
338
|
+
textAlign: "left",
|
|
339
|
+
width: "100%",
|
|
340
|
+
maxWidth: "300px",
|
|
341
|
+
boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.05)",
|
|
342
|
+
},
|
|
236
343
|
};
|
|
344
|
+
const ANIMATION_STYLES = `
|
|
345
|
+
@keyframes sh-fade-in {
|
|
346
|
+
from {
|
|
347
|
+
opacity: 0;
|
|
348
|
+
transform: translate(-50%, -48%) scale(0.96);
|
|
349
|
+
}
|
|
350
|
+
to {
|
|
351
|
+
opacity: 1;
|
|
352
|
+
transform: translate(-50%, -50%) scale(1);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
@keyframes sh-fade-out {
|
|
356
|
+
from {
|
|
357
|
+
opacity: 1;
|
|
358
|
+
transform: translate(-50%, -50%) scale(1);
|
|
359
|
+
}
|
|
360
|
+
to {
|
|
361
|
+
opacity: 0;
|
|
362
|
+
transform: translate(-50%, -48%) scale(0.96);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
@keyframes sh-backdrop-fade-in {
|
|
366
|
+
from {
|
|
367
|
+
opacity: 0;
|
|
368
|
+
}
|
|
369
|
+
to {
|
|
370
|
+
opacity: 1;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
@keyframes sh-backdrop-fade-out {
|
|
374
|
+
from {
|
|
375
|
+
opacity: 1;
|
|
376
|
+
}
|
|
377
|
+
to {
|
|
378
|
+
opacity: 0;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
.sh-dialog-animate {
|
|
382
|
+
animation: sh-fade-in 0.22s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
383
|
+
}
|
|
384
|
+
.sh-dialog-animate-out {
|
|
385
|
+
animation: sh-fade-out 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
386
|
+
}
|
|
387
|
+
.sh-backdrop-animate {
|
|
388
|
+
animation: sh-backdrop-fade-in 0.18s ease-out forwards;
|
|
389
|
+
}
|
|
390
|
+
.sh-backdrop-animate-out {
|
|
391
|
+
animation: sh-backdrop-fade-out 0.18s ease-out forwards;
|
|
392
|
+
}
|
|
393
|
+
.sh-feedback-btn {
|
|
394
|
+
color: #a1a1aa;
|
|
395
|
+
border-radius: 4px;
|
|
396
|
+
transition: color 0.2s, background-color 0.2s;
|
|
397
|
+
}
|
|
398
|
+
.sh-feedback-btn:hover {
|
|
399
|
+
background-color: #f4f4f5 !important;
|
|
400
|
+
color: #3f3f46 !important;
|
|
401
|
+
}
|
|
402
|
+
.sh-header-btn {
|
|
403
|
+
transition: all 0.2s;
|
|
404
|
+
}
|
|
405
|
+
.sh-header-btn:hover {
|
|
406
|
+
background-color: #f9fafb !important;
|
|
407
|
+
border-color: #d1d5db !important;
|
|
408
|
+
}
|
|
409
|
+
`;
|
|
237
410
|
const TRANSLATIONS = {
|
|
238
411
|
newChat: "New Chat",
|
|
239
412
|
welcomeToShopPrompter: "Welcome to ShopPrompter",
|
|
@@ -241,9 +414,8 @@ const TRANSLATIONS = {
|
|
|
241
414
|
"I am your personal AI shopping assistant. Ask me anything about our products!",
|
|
242
415
|
askMeAnything: "Ask me anything...",
|
|
243
416
|
thinking: "Thinking...",
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
findByBudget: "Find by budget",
|
|
417
|
+
feedbackError:
|
|
418
|
+
"We are sorry, but we could not process your feedback. Please try again later.",
|
|
247
419
|
};
|
|
248
420
|
const ICONS = {
|
|
249
421
|
chat: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/message-square.svg",
|
|
@@ -253,8 +425,6 @@ const ICONS = {
|
|
|
253
425
|
"https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/fire.svg",
|
|
254
426
|
compareproducts:
|
|
255
427
|
"https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/box.svg",
|
|
256
|
-
findbybudget:
|
|
257
|
-
"https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/foto.svg",
|
|
258
428
|
sendHorizontal:
|
|
259
429
|
"https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/send-horizontal.svg",
|
|
260
430
|
};
|
|
@@ -268,42 +438,116 @@ function ShopPrompter(props) {
|
|
|
268
438
|
|
|
269
439
|
const [chatMessages, setChatMessages] = useState(() => []);
|
|
270
440
|
|
|
271
|
-
const [showChat, setShowChat] = useState(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
441
|
+
const [showChat, setShowChat] = useState(() => false);
|
|
442
|
+
|
|
443
|
+
const [isClosing, setIsClosing] = useState(() => false);
|
|
444
|
+
|
|
445
|
+
const [closeTimeout, setCloseTimeout] = useState(() => null);
|
|
275
446
|
|
|
276
447
|
const [service, setService] = useState(() => null);
|
|
277
448
|
|
|
278
|
-
const [
|
|
279
|
-
|
|
449
|
+
const [agentExperience, setAgentExperience] = useState(() => null);
|
|
450
|
+
|
|
451
|
+
const [animationClass, setAnimationClass] = useState(() => "");
|
|
452
|
+
|
|
453
|
+
const [backdropAnimationClass, setBackdropAnimationClass] = useState(
|
|
454
|
+
() => ""
|
|
280
455
|
);
|
|
281
456
|
|
|
282
|
-
|
|
457
|
+
function hasToken() {
|
|
458
|
+
const token =
|
|
459
|
+
props.shopPrompterToken || apiConfigObj?.()?.shopPrompterToken;
|
|
460
|
+
return !!token;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function isConfigInsufficient() {
|
|
464
|
+
const token =
|
|
465
|
+
props.shopPrompterToken || apiConfigObj?.()?.shopPrompterToken;
|
|
466
|
+
const apiKey = apiConfigObj?.()?.apiKey;
|
|
467
|
+
return !token && !apiKey;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function showPriceIfEmptyVal() {
|
|
471
|
+
const val = props.showPriceIfEmpty;
|
|
472
|
+
if (typeof val === "string") {
|
|
473
|
+
return val === "true";
|
|
474
|
+
}
|
|
475
|
+
return val ?? false;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function visibleFieldsList() {
|
|
479
|
+
const val = props.visibleFields;
|
|
480
|
+
if (typeof val === "string") {
|
|
481
|
+
try {
|
|
482
|
+
return JSON.parse(val);
|
|
483
|
+
} catch (e) {
|
|
484
|
+
return val
|
|
485
|
+
.split(",")
|
|
486
|
+
.map((s) => s.trim())
|
|
487
|
+
.filter(Boolean);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return val || [];
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function themeObj() {
|
|
494
|
+
if (typeof props.theme === "string") {
|
|
495
|
+
try {
|
|
496
|
+
return JSON.parse(props.theme);
|
|
497
|
+
} catch (e) {
|
|
498
|
+
return {};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return props.theme || {};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function prompts() {
|
|
505
|
+
return agentExperience?.predefinedPrompts || [];
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function apiConfigObj() {
|
|
509
|
+
if (typeof props.apiConfig === "string") {
|
|
510
|
+
try {
|
|
511
|
+
return JSON.parse(props.apiConfig);
|
|
512
|
+
} catch (e) {
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return props.apiConfig || null;
|
|
517
|
+
}
|
|
283
518
|
|
|
284
519
|
function containerStyle() {
|
|
285
520
|
const pos = props.chatPosition || "classic-chatbot";
|
|
286
521
|
const isFull = pos === "full-page";
|
|
287
|
-
const
|
|
522
|
+
const isDialog = pos === "dialog";
|
|
288
523
|
const isClassic = pos === "classic-chatbot";
|
|
289
524
|
const isRight = pos === "right-panel";
|
|
290
525
|
return {
|
|
291
526
|
position: isFull ? "relative" : "fixed",
|
|
292
|
-
bottom: isClassic ? "1rem" :
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
527
|
+
bottom: isClassic ? "1rem" : isDialog ? "auto" : "0",
|
|
528
|
+
top: isDialog ? "50%" : "auto",
|
|
529
|
+
right: isClassic || isRight ? "1rem" : isDialog ? "auto" : "0",
|
|
530
|
+
left: isDialog ? "50%" : isClassic || isRight || isFull ? "auto" : "0",
|
|
531
|
+
transform: isDialog ? "translate(-50%, -50%)" : "none",
|
|
532
|
+
width: isFull ? "100%" : isDialog ? "90%" : "24rem",
|
|
533
|
+
height: isClassic
|
|
534
|
+
? "550px"
|
|
535
|
+
: isDialog
|
|
536
|
+
? "700px"
|
|
537
|
+
: isFull
|
|
538
|
+
? "600px"
|
|
539
|
+
: "100%",
|
|
540
|
+
maxWidth: isDialog ? "900px" : "none",
|
|
541
|
+
maxHeight: isDialog ? "90vh" : "none",
|
|
542
|
+
zIndex: isDialog ? 1001 : isClassic || isRight ? 1001 : 50,
|
|
543
|
+
backgroundColor: themeObj().mainBackgroundColor || "white",
|
|
301
544
|
display: "flex",
|
|
302
545
|
flexDirection: "column",
|
|
303
546
|
overflow: "hidden",
|
|
304
547
|
borderRadius: isFull ? "0" : "0.5rem",
|
|
305
548
|
border: isFull ? "none" : "1px solid #e5e7eb",
|
|
306
549
|
boxShadow: isFull ? "none" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
|
550
|
+
fontFamily: themeObj().fontFamily || undefined,
|
|
307
551
|
};
|
|
308
552
|
}
|
|
309
553
|
|
|
@@ -311,32 +555,33 @@ function ShopPrompter(props) {
|
|
|
311
555
|
const pos = props.chatPosition || "classic-chatbot";
|
|
312
556
|
if (pos === "classic-chatbot") return "sh-classic";
|
|
313
557
|
if (pos === "right-panel") return "sh-right";
|
|
314
|
-
if (pos === "
|
|
558
|
+
if (pos === "dialog") {
|
|
559
|
+
return "sh-dialog " + animationClass;
|
|
560
|
+
}
|
|
315
561
|
return "sh-full";
|
|
316
562
|
}
|
|
317
563
|
|
|
318
564
|
function messages() {
|
|
319
|
-
return chatMessages
|
|
320
|
-
...msg,
|
|
321
|
-
safeProductSkus: msg.productSkus || [],
|
|
322
|
-
}));
|
|
565
|
+
return chatMessages;
|
|
323
566
|
}
|
|
324
567
|
|
|
325
|
-
function
|
|
326
|
-
|
|
568
|
+
function parseMarkdown(content) {
|
|
569
|
+
if (!content) return "";
|
|
570
|
+
return String(marked.parse(content));
|
|
327
571
|
}
|
|
328
572
|
|
|
329
|
-
function
|
|
330
|
-
return
|
|
573
|
+
function showWelcome() {
|
|
574
|
+
return chatMessages.length === 0;
|
|
331
575
|
}
|
|
332
576
|
|
|
333
|
-
function
|
|
334
|
-
return
|
|
577
|
+
function getShowProducts(message) {
|
|
578
|
+
return message.productSkus && message.productSkus.length > 0;
|
|
335
579
|
}
|
|
336
580
|
|
|
337
|
-
function handleSend() {
|
|
338
|
-
|
|
339
|
-
|
|
581
|
+
function handleSend(overrideQuery) {
|
|
582
|
+
const actualQuery = overrideQuery || input;
|
|
583
|
+
if (!actualQuery.trim() || isLoading) return;
|
|
584
|
+
const userQuery = actualQuery;
|
|
340
585
|
setInput("");
|
|
341
586
|
const userMsg = {
|
|
342
587
|
id: Date.now().toString() + "-user",
|
|
@@ -344,30 +589,45 @@ function ShopPrompter(props) {
|
|
|
344
589
|
content: userQuery,
|
|
345
590
|
productSkus: [],
|
|
346
591
|
};
|
|
347
|
-
setChatMessages([...chatMessages, userMsg]);
|
|
348
592
|
const assistantMsg = {
|
|
349
593
|
id: Date.now().toString() + "-assistant",
|
|
350
594
|
role: "assistant",
|
|
351
595
|
content: "",
|
|
352
596
|
productSkus: [],
|
|
353
597
|
};
|
|
354
|
-
|
|
598
|
+
let currentMessages = [...chatMessages, userMsg, assistantMsg];
|
|
599
|
+
setChatMessages(currentMessages);
|
|
600
|
+
setTimeout(() => {
|
|
601
|
+
const inputEl = document.getElementById("shop-prompter-input");
|
|
602
|
+
if (inputEl) {
|
|
603
|
+
inputEl.value = "";
|
|
604
|
+
inputEl.focus();
|
|
605
|
+
}
|
|
606
|
+
}, 0);
|
|
355
607
|
service?.sendMessage(
|
|
356
608
|
userQuery,
|
|
357
609
|
{
|
|
358
610
|
onTextUpdate: (text) => {
|
|
359
|
-
const updatedMessages = [...
|
|
611
|
+
const updatedMessages = [...currentMessages];
|
|
360
612
|
const lastMsg = updatedMessages[updatedMessages.length - 1];
|
|
361
613
|
if (lastMsg) {
|
|
362
|
-
|
|
614
|
+
updatedMessages[updatedMessages.length - 1] = {
|
|
615
|
+
...lastMsg,
|
|
616
|
+
content: text,
|
|
617
|
+
};
|
|
618
|
+
currentMessages = updatedMessages;
|
|
363
619
|
setChatMessages(updatedMessages);
|
|
364
620
|
}
|
|
365
621
|
},
|
|
366
622
|
onProductSkus: (skus) => {
|
|
367
|
-
const updatedMessages = [...
|
|
623
|
+
const updatedMessages = [...currentMessages];
|
|
368
624
|
const lastMsg = updatedMessages[updatedMessages.length - 1];
|
|
369
625
|
if (lastMsg) {
|
|
370
|
-
|
|
626
|
+
updatedMessages[updatedMessages.length - 1] = {
|
|
627
|
+
...lastMsg,
|
|
628
|
+
productSkus: skus,
|
|
629
|
+
};
|
|
630
|
+
currentMessages = updatedMessages;
|
|
371
631
|
setChatMessages(updatedMessages);
|
|
372
632
|
}
|
|
373
633
|
},
|
|
@@ -381,16 +641,65 @@ function ShopPrompter(props) {
|
|
|
381
641
|
if (props.onCartOperation) {
|
|
382
642
|
props.onCartOperation(ops);
|
|
383
643
|
}
|
|
644
|
+
dispatchCartOperation(ops);
|
|
384
645
|
},
|
|
385
646
|
},
|
|
386
647
|
props.cart || []
|
|
387
648
|
);
|
|
388
649
|
}
|
|
389
650
|
|
|
651
|
+
function dispatchCartOperation(ops) {
|
|
652
|
+
if (typeof window !== "undefined") {
|
|
653
|
+
const root =
|
|
654
|
+
typeof self !== "undefined" &&
|
|
655
|
+
self &&
|
|
656
|
+
"dispatchEvent" in self &&
|
|
657
|
+
!(self instanceof Window)
|
|
658
|
+
? self
|
|
659
|
+
: null;
|
|
660
|
+
if (root) {
|
|
661
|
+
root.dispatchEvent(
|
|
662
|
+
new CustomEvent("cartOperation", {
|
|
663
|
+
detail: ops,
|
|
664
|
+
})
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
390
670
|
function toggleChat() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
671
|
+
if (showChat) {
|
|
672
|
+
setIsClosing(true);
|
|
673
|
+
setAnimationClass("sh-dialog-animate-out");
|
|
674
|
+
setBackdropAnimationClass("sh-backdrop-animate-out");
|
|
675
|
+
if (closeTimeout) {
|
|
676
|
+
clearTimeout(closeTimeout);
|
|
677
|
+
}
|
|
678
|
+
setCloseTimeout(
|
|
679
|
+
setTimeout(() => {
|
|
680
|
+
setShowChat(false);
|
|
681
|
+
setIsClosing(false);
|
|
682
|
+
setAnimationClass("");
|
|
683
|
+
setBackdropAnimationClass("");
|
|
684
|
+
setCloseTimeout(null);
|
|
685
|
+
if (props.onClose) {
|
|
686
|
+
props.onClose();
|
|
687
|
+
}
|
|
688
|
+
}, 200)
|
|
689
|
+
);
|
|
690
|
+
} else {
|
|
691
|
+
if (closeTimeout) {
|
|
692
|
+
clearTimeout(closeTimeout);
|
|
693
|
+
setCloseTimeout(null);
|
|
694
|
+
}
|
|
695
|
+
setShowChat(true);
|
|
696
|
+
setIsClosing(false);
|
|
697
|
+
setAnimationClass("sh-dialog-animate");
|
|
698
|
+
setBackdropAnimationClass("sh-backdrop-animate");
|
|
699
|
+
setTimeout(() => {
|
|
700
|
+
setAnimationClass("");
|
|
701
|
+
setBackdropAnimationClass("");
|
|
702
|
+
}, 250);
|
|
394
703
|
}
|
|
395
704
|
}
|
|
396
705
|
|
|
@@ -399,16 +708,6 @@ function ShopPrompter(props) {
|
|
|
399
708
|
service?.resetSession();
|
|
400
709
|
}
|
|
401
710
|
|
|
402
|
-
function onPopularItemsClick() {
|
|
403
|
-
setInput(TRANSLATIONS.showPopularItems);
|
|
404
|
-
handleSend();
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function onCompareProductsClick() {
|
|
408
|
-
setInput(TRANSLATIONS.compareProducts);
|
|
409
|
-
handleSend();
|
|
410
|
-
}
|
|
411
|
-
|
|
412
711
|
function onInputChange(event) {
|
|
413
712
|
setInput(event.target.value);
|
|
414
713
|
}
|
|
@@ -419,53 +718,235 @@ function ShopPrompter(props) {
|
|
|
419
718
|
}
|
|
420
719
|
}
|
|
421
720
|
|
|
422
|
-
function
|
|
423
|
-
|
|
721
|
+
function handleTriggerClick(e) {
|
|
722
|
+
if (props.chatPosition !== "dialog") return;
|
|
723
|
+
if (!props.dialogTrigger) return;
|
|
724
|
+
const isTargetClicked =
|
|
725
|
+
typeof props.dialogTrigger === "string"
|
|
726
|
+
? e.target.closest(props.dialogTrigger)
|
|
727
|
+
: (() => {
|
|
728
|
+
let target = null;
|
|
729
|
+
if (typeof props.dialogTrigger === "object") {
|
|
730
|
+
if ("current" in props.dialogTrigger) {
|
|
731
|
+
target = props.dialogTrigger.current;
|
|
732
|
+
} else {
|
|
733
|
+
target = props.dialogTrigger;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
return target && target.contains && target.contains(e.target);
|
|
737
|
+
})();
|
|
738
|
+
if (isTargetClicked) {
|
|
739
|
+
if (closeTimeout) {
|
|
740
|
+
clearTimeout(closeTimeout);
|
|
741
|
+
setCloseTimeout(null);
|
|
742
|
+
}
|
|
743
|
+
setShowChat(true);
|
|
744
|
+
setIsClosing(false);
|
|
745
|
+
setAnimationClass("sh-dialog-animate");
|
|
746
|
+
setBackdropAnimationClass("sh-backdrop-animate");
|
|
747
|
+
setTimeout(() => {
|
|
748
|
+
setAnimationClass("");
|
|
749
|
+
setBackdropAnimationClass("");
|
|
750
|
+
}, 250);
|
|
751
|
+
}
|
|
424
752
|
}
|
|
425
753
|
|
|
426
|
-
function
|
|
427
|
-
|
|
754
|
+
function loadCustomFont(fontFamily) {
|
|
755
|
+
if (!fontFamily || typeof window === "undefined") return;
|
|
756
|
+
const systemFonts = [
|
|
757
|
+
"sans-serif",
|
|
758
|
+
"serif",
|
|
759
|
+
"monospace",
|
|
760
|
+
"cursive",
|
|
761
|
+
"fantasy",
|
|
762
|
+
"system-ui",
|
|
763
|
+
"-apple-system",
|
|
764
|
+
"blinkmacsystemfont",
|
|
765
|
+
"segoe ui",
|
|
766
|
+
"roboto",
|
|
767
|
+
"helvetica",
|
|
768
|
+
"arial",
|
|
769
|
+
"inherit",
|
|
770
|
+
];
|
|
771
|
+
const cleanFont = fontFamily
|
|
772
|
+
.split(",")[0]
|
|
773
|
+
.trim()
|
|
774
|
+
.replace(new RegExp("['\"]", "g"), "");
|
|
775
|
+
if (!cleanFont || systemFonts.includes(cleanFont.toLowerCase())) return;
|
|
776
|
+
const linkId = `shopprompter-font-${cleanFont
|
|
777
|
+
.toLowerCase()
|
|
778
|
+
.replace(new RegExp("\\s+", "g"), "-")}`;
|
|
779
|
+
if (document.getElementById(linkId)) return;
|
|
780
|
+
const link = document.createElement("link");
|
|
781
|
+
link.id = linkId;
|
|
782
|
+
link.rel = "stylesheet";
|
|
783
|
+
const fontNameUrl = cleanFont.replace(new RegExp("\\s+", "g"), "+");
|
|
784
|
+
link.href = `https://fonts.googleapis.com/css2?family=${fontNameUrl}:wght@400;500;600;700&display=swap`;
|
|
785
|
+
document.head.appendChild(link);
|
|
428
786
|
}
|
|
429
787
|
|
|
430
|
-
function
|
|
788
|
+
function loadAgentExperience() {
|
|
431
789
|
void (async function () {
|
|
432
|
-
console.log("## ~ ShopPrompter ~ state.service:", service);
|
|
433
790
|
if (!service) {
|
|
434
|
-
console.warn(
|
|
791
|
+
console.warn(
|
|
792
|
+
"Service not initialized yet! Cannot load AgentExperience."
|
|
793
|
+
);
|
|
435
794
|
return;
|
|
436
795
|
}
|
|
437
796
|
const response = await service?.getAgentExperience();
|
|
438
|
-
console.log("## ~ ShopPrompter ~ response:", response);
|
|
439
797
|
setAgentExperience(response);
|
|
440
798
|
})();
|
|
441
799
|
}
|
|
442
800
|
|
|
801
|
+
function handleFeedback(messageId, messageContent, newFeedback) {
|
|
802
|
+
const msg = chatMessages.find((m) => m.id === messageId);
|
|
803
|
+
if (!msg) return;
|
|
804
|
+
const currentFeedback = msg.feedback;
|
|
805
|
+
const targetFeedback =
|
|
806
|
+
currentFeedback === newFeedback ? "clear" : newFeedback;
|
|
807
|
+
|
|
808
|
+
// Optimistically update the UI state
|
|
809
|
+
const oldMessages = [...chatMessages];
|
|
810
|
+
setChatMessages(
|
|
811
|
+
chatMessages.map((m) => {
|
|
812
|
+
if (m.id === messageId) {
|
|
813
|
+
return {
|
|
814
|
+
...m,
|
|
815
|
+
feedback: targetFeedback === "clear" ? null : targetFeedback,
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
return m;
|
|
819
|
+
})
|
|
820
|
+
);
|
|
821
|
+
setError(null);
|
|
822
|
+
service
|
|
823
|
+
?.sendFeedback(messageId, messageContent, targetFeedback)
|
|
824
|
+
.catch((err) => {
|
|
825
|
+
// Revert optimistic update
|
|
826
|
+
setChatMessages(oldMessages);
|
|
827
|
+
setError(err?.message || TRANSLATIONS.feedbackError);
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
function canShowFeedback(message) {
|
|
832
|
+
if (message.role !== "assistant") return false;
|
|
833
|
+
if (!message.content) return false;
|
|
834
|
+
const lastMsg = chatMessages[chatMessages.length - 1];
|
|
835
|
+
if (lastMsg && lastMsg.id === message.id && isLoading) {
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
|
|
443
841
|
useEffect(() => {
|
|
444
|
-
|
|
445
|
-
|
|
842
|
+
if (
|
|
843
|
+
typeof window !== "undefined" &&
|
|
844
|
+
!document.getElementById("lottie-player-script")
|
|
845
|
+
) {
|
|
846
|
+
const script = document.createElement("script");
|
|
847
|
+
script.id = "lottie-player-script";
|
|
848
|
+
script.src =
|
|
849
|
+
"https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player";
|
|
850
|
+
document.head.appendChild(script);
|
|
851
|
+
}
|
|
852
|
+
if (themeObj().fontFamily) {
|
|
853
|
+
loadCustomFont(themeObj().fontFamily);
|
|
854
|
+
}
|
|
855
|
+
if (apiConfigObj()) {
|
|
856
|
+
if (!isConfigInsufficient()) {
|
|
857
|
+
const apiConfig = {
|
|
858
|
+
...apiConfigObj(),
|
|
859
|
+
shopPrompterToken:
|
|
860
|
+
props.shopPrompterToken || apiConfigObj().shopPrompterToken,
|
|
861
|
+
};
|
|
862
|
+
const service = new ShopPrompterService(apiConfig);
|
|
863
|
+
setService(service);
|
|
864
|
+
// Restore persisted messages for the current session.
|
|
865
|
+
const savedMessages = service.loadMessages();
|
|
866
|
+
if (savedMessages.length > 0) {
|
|
867
|
+
setChatMessages(savedMessages);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
} else {
|
|
871
|
+
console.error("ShopPrompter: apiConfig prop is required!");
|
|
872
|
+
}
|
|
873
|
+
if (
|
|
874
|
+
props?.chatPosition === "right-panel" ||
|
|
875
|
+
props?.chatPosition === "full-page"
|
|
876
|
+
) {
|
|
877
|
+
setShowChat(true);
|
|
878
|
+
}
|
|
879
|
+
if (typeof window !== "undefined") {
|
|
880
|
+
document.addEventListener("click", handleTriggerClick);
|
|
881
|
+
}
|
|
446
882
|
}, []);
|
|
447
883
|
useEffect(() => {
|
|
448
884
|
if (service && !agentExperience) {
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
if (agentExperience) {
|
|
452
|
-
console.log("## ~ ShopPrompter ~ agentExperience updated:", {
|
|
453
|
-
greeting: agentExperience.greeting,
|
|
454
|
-
agentLogoUrl: agentExperience.agentLogoUrl,
|
|
455
|
-
});
|
|
885
|
+
loadAgentExperience();
|
|
456
886
|
}
|
|
457
887
|
}, [service, agentExperience]);
|
|
888
|
+
useEffect(() => {
|
|
889
|
+
if (themeObj().fontFamily) {
|
|
890
|
+
loadCustomFont(themeObj().fontFamily);
|
|
891
|
+
}
|
|
892
|
+
}, [themeObj().fontFamily || ""]);
|
|
893
|
+
useEffect(() => {
|
|
894
|
+
if (
|
|
895
|
+
props?.chatPosition === "right-panel" ||
|
|
896
|
+
props?.chatPosition === "full-page"
|
|
897
|
+
) {
|
|
898
|
+
setShowChat(true);
|
|
899
|
+
} else if (
|
|
900
|
+
props?.chatPosition === "dialog" ||
|
|
901
|
+
props?.chatPosition === "classic-chatbot"
|
|
902
|
+
) {
|
|
903
|
+
setShowChat(false);
|
|
904
|
+
setIsClosing(false);
|
|
905
|
+
setAnimationClass("");
|
|
906
|
+
setBackdropAnimationClass("");
|
|
907
|
+
}
|
|
908
|
+
}, [props?.chatPosition || ""]);
|
|
458
909
|
|
|
459
910
|
return (
|
|
460
911
|
<div className="shopprompter-sdk">
|
|
912
|
+
<style dangerouslySetInnerHTML={{ __html: ANIMATION_STYLES }} />
|
|
913
|
+
<div
|
|
914
|
+
onClick={(e) => toggleChat()}
|
|
915
|
+
style={{
|
|
916
|
+
...styles.backdrop,
|
|
917
|
+
display:
|
|
918
|
+
props.chatPosition === "dialog" && (showChat || isClosing)
|
|
919
|
+
? "block"
|
|
920
|
+
: "none",
|
|
921
|
+
}}
|
|
922
|
+
className={backdropAnimationClass}
|
|
923
|
+
/>
|
|
461
924
|
{props.chatPosition === "classic-chatbot" ? (
|
|
462
925
|
<>
|
|
463
926
|
{!showChat ? (
|
|
464
927
|
<button
|
|
465
|
-
className="fixed bottom-6 right-6 w-16 h-16 bg-blue-600 hover:bg-blue-700 rounded-full shadow-lg z-50 flex items-center justify-center transition-colors border-none cursor-pointer"
|
|
466
928
|
onClick={(e) => toggleChat()}
|
|
467
929
|
style={{
|
|
468
|
-
|
|
930
|
+
position: "fixed",
|
|
931
|
+
bottom: "1.5rem",
|
|
932
|
+
right: "1.5rem",
|
|
933
|
+
width: "4rem",
|
|
934
|
+
height: "4rem",
|
|
935
|
+
backgroundColor: themeObj().actionColor || "#2563eb",
|
|
936
|
+
borderRadius: "9999px",
|
|
937
|
+
zIndex: 50,
|
|
938
|
+
display: "flex",
|
|
939
|
+
alignItems: "center",
|
|
940
|
+
justifyContent: "center",
|
|
941
|
+
transition: "background-color 0.2s",
|
|
942
|
+
border: "none",
|
|
943
|
+
cursor: "pointer",
|
|
944
|
+
boxShadow: themeObj().actionColor
|
|
945
|
+
? `0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05), 0 0 0 8px ${
|
|
946
|
+
themeObj().actionColor
|
|
947
|
+
}33`
|
|
948
|
+
: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05), 0 0 0 8px rgba(37, 99, 235, 0.2)",
|
|
949
|
+
fontFamily: themeObj().fontFamily || undefined,
|
|
469
950
|
}}
|
|
470
951
|
>
|
|
471
952
|
<img
|
|
@@ -480,107 +961,56 @@ function ShopPrompter(props) {
|
|
|
480
961
|
) : null}
|
|
481
962
|
</>
|
|
482
963
|
) : null}
|
|
483
|
-
{showChat ? (
|
|
964
|
+
{showChat || isClosing ? (
|
|
484
965
|
<div style={containerStyle()} className={containerClass()}>
|
|
485
|
-
<div
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
>
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
</linearGradient>
|
|
523
|
-
<linearGradient
|
|
524
|
-
id="b"
|
|
525
|
-
x1="21.156"
|
|
526
|
-
x2="40.431"
|
|
527
|
-
y1="21.216"
|
|
528
|
-
y2="1.624"
|
|
529
|
-
gradientUnits="userSpaceOnUse"
|
|
530
|
-
>
|
|
531
|
-
<stop offset=".08" stopColor="#E7A2FF" />
|
|
532
|
-
<stop offset=".37" stopColor="#E983CD" />
|
|
533
|
-
<stop offset=".99" stopColor="#F03A58" />
|
|
534
|
-
</linearGradient>
|
|
535
|
-
<linearGradient
|
|
536
|
-
id="c"
|
|
537
|
-
x1="30.464"
|
|
538
|
-
x2="46.567"
|
|
539
|
-
y1="27.405"
|
|
540
|
-
y2="42.472"
|
|
541
|
-
gradientUnits="userSpaceOnUse"
|
|
542
|
-
>
|
|
543
|
-
<stop stopColor="#B0145C" />
|
|
544
|
-
<stop offset=".02" stopColor="#B11861" />
|
|
545
|
-
<stop offset=".27" stopColor="#C44999" />
|
|
546
|
-
<stop offset=".5" stopColor="#D36FC5" />
|
|
547
|
-
<stop offset=".71" stopColor="#DE8BE4" />
|
|
548
|
-
<stop offset=".88" stopColor="#E49BF8" />
|
|
549
|
-
<stop offset="1" stopColor="#E7A2FF" />
|
|
550
|
-
</linearGradient>
|
|
551
|
-
<linearGradient
|
|
552
|
-
id="d"
|
|
553
|
-
x1="23.356"
|
|
554
|
-
x2="-.618"
|
|
555
|
-
y1="44.082"
|
|
556
|
-
y2="30.739"
|
|
557
|
-
gradientUnits="userSpaceOnUse"
|
|
558
|
-
>
|
|
559
|
-
<stop stopColor="#AD59FF" />
|
|
560
|
-
<stop offset=".1" stopColor="#B455EB" />
|
|
561
|
-
<stop offset=".54" stopColor="#D4469C" />
|
|
562
|
-
<stop offset=".85" stopColor="#E83D6B" />
|
|
563
|
-
<stop offset="1" stopColor="#F03A58" />
|
|
564
|
-
</linearGradient>
|
|
565
|
-
</defs>
|
|
566
|
-
</svg>
|
|
567
|
-
<span style={styles.headerText}>ShopPrompter®</span>
|
|
568
|
-
</div>
|
|
966
|
+
<div
|
|
967
|
+
style={{
|
|
968
|
+
...styles.header,
|
|
969
|
+
backgroundColor:
|
|
970
|
+
themeObj().headerBackgroundColor || "transparent",
|
|
971
|
+
}}
|
|
972
|
+
>
|
|
973
|
+
{themeObj().showAgentName !== false ? (
|
|
974
|
+
<div style={styles.subHeaderContainer}>
|
|
975
|
+
{agentExperience?.agentLogoUrl ? (
|
|
976
|
+
<img
|
|
977
|
+
src={agentExperience.agentLogoUrl}
|
|
978
|
+
alt={agentExperience.agentName}
|
|
979
|
+
style={{
|
|
980
|
+
width: "24px",
|
|
981
|
+
height: "24px",
|
|
982
|
+
borderRadius: "4px",
|
|
983
|
+
objectFit: "cover",
|
|
984
|
+
}}
|
|
985
|
+
/>
|
|
986
|
+
) : null}
|
|
987
|
+
{agentExperience?.agentName ? (
|
|
988
|
+
<span style={styles.headerText}>
|
|
989
|
+
{agentExperience.agentName}
|
|
990
|
+
</span>
|
|
991
|
+
) : null}
|
|
992
|
+
</div>
|
|
993
|
+
) : (
|
|
994
|
+
<>
|
|
995
|
+
<div style={styles.subHeaderContainer} />
|
|
996
|
+
</>
|
|
997
|
+
)}
|
|
998
|
+
{!hasToken() && apiConfigObj?.()?.apiKey ? (
|
|
999
|
+
<div style={styles.warningBanner}>
|
|
1000
|
+
API Key is only for development purposes
|
|
1001
|
+
</div>
|
|
1002
|
+
) : null}
|
|
569
1003
|
<div style={styles.subHeaderContainer}>
|
|
570
1004
|
<button
|
|
1005
|
+
className="sh-header-btn"
|
|
571
1006
|
onClick={(e) => handleNewChat()}
|
|
572
|
-
|
|
573
|
-
onMouseLeave={(e) => onHeaderButtonMouseLeave()}
|
|
574
|
-
style={{
|
|
575
|
-
...styles.headerButton,
|
|
576
|
-
...(isHeaderButtonHovered ? styles.headerButton.onHover : {}),
|
|
577
|
-
}}
|
|
1007
|
+
style={styles.headerButton}
|
|
578
1008
|
>
|
|
579
1009
|
{TRANSLATIONS.newChat}
|
|
580
1010
|
</button>
|
|
581
1011
|
{props.chatPosition === "classic-chatbot" ||
|
|
582
1012
|
props.chatPosition === "right-panel" ||
|
|
583
|
-
props.chatPosition === "
|
|
1013
|
+
props.chatPosition === "dialog" ? (
|
|
584
1014
|
<button
|
|
585
1015
|
onClick={(e) => toggleChat()}
|
|
586
1016
|
style={styles.ButtonSheetButton}
|
|
@@ -590,135 +1020,351 @@ function ShopPrompter(props) {
|
|
|
590
1020
|
) : null}
|
|
591
1021
|
</div>
|
|
592
1022
|
</div>
|
|
593
|
-
|
|
594
|
-
{
|
|
595
|
-
<div style={styles.
|
|
596
|
-
<
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
1023
|
+
{isConfigInsufficient() ? (
|
|
1024
|
+
<div style={styles.insufficientConfigContainer}>
|
|
1025
|
+
<div style={styles.insufficientConfigIconContainer}>
|
|
1026
|
+
<svg
|
|
1027
|
+
width="48"
|
|
1028
|
+
height="48"
|
|
1029
|
+
viewBox="0 0 24 24"
|
|
1030
|
+
fill="none"
|
|
1031
|
+
stroke="currentColor"
|
|
1032
|
+
strokeWidth="2"
|
|
1033
|
+
strokeLinecap="round"
|
|
1034
|
+
strokeLinejoin="round"
|
|
603
1035
|
style={{
|
|
604
|
-
|
|
605
|
-
height: "64px",
|
|
606
|
-
marginBottom: "24px",
|
|
1036
|
+
color: "#ef4444",
|
|
607
1037
|
}}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
1038
|
+
>
|
|
1039
|
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" />
|
|
1040
|
+
<path d="M7 11V7a5 5 0 0 1 9.9-1" />
|
|
1041
|
+
</svg>
|
|
1042
|
+
</div>
|
|
1043
|
+
<h3
|
|
1044
|
+
style={{
|
|
1045
|
+
...styles.insufficientConfigTitle,
|
|
1046
|
+
fontFamily: themeObj().fontFamily || undefined,
|
|
1047
|
+
}}
|
|
1048
|
+
>
|
|
1049
|
+
Configuration Error
|
|
1050
|
+
</h3>
|
|
1051
|
+
<p
|
|
1052
|
+
style={{
|
|
1053
|
+
...styles.insufficientConfigMessage,
|
|
1054
|
+
fontFamily: themeObj().fontFamily || undefined,
|
|
1055
|
+
}}
|
|
1056
|
+
>
|
|
1057
|
+
ShopPrompter requires a secure token or API key to initialize.
|
|
1058
|
+
Please check your setup.
|
|
1059
|
+
</p>
|
|
1060
|
+
<div
|
|
1061
|
+
style={{
|
|
1062
|
+
...styles.insufficientConfigDetails,
|
|
1063
|
+
fontFamily: themeObj().fontFamily || undefined,
|
|
1064
|
+
}}
|
|
1065
|
+
>
|
|
1066
|
+
<div
|
|
1067
|
+
style={{
|
|
1068
|
+
fontWeight: 600,
|
|
1069
|
+
marginBottom: "0.25rem",
|
|
1070
|
+
}}
|
|
1071
|
+
>
|
|
1072
|
+
Missing Parameters:
|
|
1073
|
+
</div>
|
|
1074
|
+
<div
|
|
1075
|
+
style={{
|
|
1076
|
+
display: "flex",
|
|
1077
|
+
flexDirection: "column",
|
|
1078
|
+
gap: "0.25rem",
|
|
1079
|
+
fontFamily: "monospace",
|
|
1080
|
+
fontSize: "0.75rem",
|
|
1081
|
+
}}
|
|
1082
|
+
>
|
|
1083
|
+
<span
|
|
1084
|
+
style={{
|
|
1085
|
+
color: "#ef4444",
|
|
1086
|
+
}}
|
|
621
1087
|
>
|
|
622
|
-
|
|
623
|
-
</
|
|
624
|
-
<
|
|
625
|
-
style={
|
|
626
|
-
|
|
1088
|
+
✗ shopPrompterToken (not found)
|
|
1089
|
+
</span>
|
|
1090
|
+
<span
|
|
1091
|
+
style={{
|
|
1092
|
+
color: "#ef4444",
|
|
1093
|
+
}}
|
|
627
1094
|
>
|
|
628
|
-
|
|
629
|
-
</
|
|
1095
|
+
✗ apiConfig.apiKey (not found)
|
|
1096
|
+
</span>
|
|
630
1097
|
</div>
|
|
631
1098
|
</div>
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
1099
|
+
</div>
|
|
1100
|
+
) : null}
|
|
1101
|
+
{!isConfigInsufficient() ? (
|
|
1102
|
+
<div
|
|
1103
|
+
style={{
|
|
1104
|
+
display: "flex",
|
|
1105
|
+
flexDirection: "column",
|
|
1106
|
+
flex: 1,
|
|
1107
|
+
overflow: "hidden",
|
|
1108
|
+
}}
|
|
1109
|
+
>
|
|
1110
|
+
<div
|
|
1111
|
+
id="shop-prompter-chat-container"
|
|
1112
|
+
style={{
|
|
1113
|
+
...styles.chatContainer,
|
|
1114
|
+
backgroundColor:
|
|
1115
|
+
themeObj().mainBackgroundColor ||
|
|
1116
|
+
styles.chatContainer.backgroundColor,
|
|
1117
|
+
}}
|
|
1118
|
+
>
|
|
1119
|
+
{showWelcome() ? (
|
|
1120
|
+
<div style={styles.welcomeContainer}>
|
|
1121
|
+
<img
|
|
1122
|
+
alt="ShopPrompter"
|
|
1123
|
+
src={
|
|
1124
|
+
agentExperience?.agentLogoUrl
|
|
1125
|
+
? agentExperience.agentLogoUrl
|
|
1126
|
+
: ICONS.shopprompter
|
|
648
1127
|
}
|
|
1128
|
+
style={{
|
|
1129
|
+
width: "64px",
|
|
1130
|
+
height: "64px",
|
|
1131
|
+
marginBottom: "24px",
|
|
1132
|
+
borderRadius: "12px",
|
|
1133
|
+
objectFit: "cover",
|
|
1134
|
+
}}
|
|
1135
|
+
/>
|
|
1136
|
+
<h3
|
|
1137
|
+
style={{
|
|
1138
|
+
...styles.welcomeTitle,
|
|
1139
|
+
fontFamily:
|
|
1140
|
+
themeObj().fontFamily ||
|
|
1141
|
+
styles.welcomeTitle.fontFamily,
|
|
1142
|
+
}}
|
|
649
1143
|
>
|
|
650
|
-
{
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
1144
|
+
{agentExperience?.greeting?.title ||
|
|
1145
|
+
TRANSLATIONS.welcomeToShopPrompter}
|
|
1146
|
+
</h3>
|
|
1147
|
+
<p
|
|
1148
|
+
style={{
|
|
1149
|
+
...styles.welcomeDescription,
|
|
1150
|
+
fontFamily:
|
|
1151
|
+
themeObj().fontFamily ||
|
|
1152
|
+
styles.welcomeDescription.fontFamily,
|
|
1153
|
+
}}
|
|
1154
|
+
>
|
|
1155
|
+
{agentExperience?.greeting?.description ||
|
|
1156
|
+
TRANSLATIONS.welcomeDescription}
|
|
1157
|
+
</p>
|
|
1158
|
+
<div style={styles.buttonContainer}>
|
|
1159
|
+
{prompts()?.map((item) => (
|
|
1160
|
+
<button
|
|
1161
|
+
key={item.prompt}
|
|
1162
|
+
style={styles.button}
|
|
1163
|
+
onClick={(event) => {
|
|
1164
|
+
setInput(item.prompt);
|
|
1165
|
+
handleSend(item.prompt);
|
|
1166
|
+
}}
|
|
1167
|
+
>
|
|
1168
|
+
{item.prompt}
|
|
1169
|
+
</button>
|
|
1170
|
+
))}
|
|
664
1171
|
</div>
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
1172
|
+
</div>
|
|
1173
|
+
) : null}
|
|
1174
|
+
{!showWelcome() ? (
|
|
1175
|
+
<div
|
|
1176
|
+
style={{
|
|
1177
|
+
width: "100%",
|
|
1178
|
+
}}
|
|
1179
|
+
>
|
|
1180
|
+
{chatMessages?.map((message) => (
|
|
1181
|
+
<div key={message.id}>
|
|
1182
|
+
{message.role === "user" ? (
|
|
1183
|
+
<div style={styles.messageContainerUser}>
|
|
1184
|
+
<div
|
|
1185
|
+
style={{
|
|
1186
|
+
...styles.messageBubbleUser,
|
|
1187
|
+
backgroundColor:
|
|
1188
|
+
themeObj().userMessageBackgroundColor ||
|
|
1189
|
+
styles.messageBubbleUser.backgroundColor,
|
|
1190
|
+
}}
|
|
1191
|
+
>
|
|
1192
|
+
{message.content}
|
|
1193
|
+
</div>
|
|
1194
|
+
</div>
|
|
1195
|
+
) : null}
|
|
1196
|
+
{message.role === "assistant" ? (
|
|
1197
|
+
<div style={styles.messageContainerAssistant}>
|
|
1198
|
+
<div
|
|
1199
|
+
style={{
|
|
1200
|
+
...styles.messageBubbleAssistant,
|
|
1201
|
+
backgroundColor:
|
|
1202
|
+
themeObj().assistantMessageBackgroundColor ||
|
|
1203
|
+
styles.messageBubbleAssistant.backgroundColor,
|
|
1204
|
+
}}
|
|
1205
|
+
>
|
|
1206
|
+
<div
|
|
1207
|
+
dangerouslySetInnerHTML={{
|
|
1208
|
+
__html: parseMarkdown(message.content),
|
|
676
1209
|
}}
|
|
677
1210
|
/>
|
|
1211
|
+
{!message.content && isLoading ? (
|
|
1212
|
+
<>
|
|
1213
|
+
{agentExperience?.loadingIndicatorUrl ? (
|
|
1214
|
+
<lottie-player
|
|
1215
|
+
background="transparent"
|
|
1216
|
+
speed="1"
|
|
1217
|
+
src={agentExperience.loadingIndicatorUrl}
|
|
1218
|
+
style={{
|
|
1219
|
+
width: "40px",
|
|
1220
|
+
height: "40px",
|
|
1221
|
+
}}
|
|
1222
|
+
loop
|
|
1223
|
+
autoplay
|
|
1224
|
+
/>
|
|
1225
|
+
) : (
|
|
1226
|
+
<div style={styles.thinkingIndicator}>
|
|
1227
|
+
<svg
|
|
1228
|
+
width="24"
|
|
1229
|
+
height="24"
|
|
1230
|
+
viewBox="0 0 24 24"
|
|
1231
|
+
fill="none"
|
|
1232
|
+
stroke="currentColor"
|
|
1233
|
+
strokeWidth="2"
|
|
1234
|
+
strokeLinecap="round"
|
|
1235
|
+
strokeLinejoin="round"
|
|
1236
|
+
style={{
|
|
1237
|
+
color: "#6b7280",
|
|
1238
|
+
}}
|
|
1239
|
+
>
|
|
1240
|
+
<path d={THINKING_SPINNER} />
|
|
1241
|
+
<animateTransform
|
|
1242
|
+
attributeName="transform"
|
|
1243
|
+
type="rotate"
|
|
1244
|
+
from="0 12 12"
|
|
1245
|
+
to="360 12 12"
|
|
1246
|
+
dur="1s"
|
|
1247
|
+
repeatCount="indefinite"
|
|
1248
|
+
/>
|
|
1249
|
+
</svg>
|
|
1250
|
+
</div>
|
|
1251
|
+
)}
|
|
1252
|
+
</>
|
|
1253
|
+
) : null}
|
|
678
1254
|
</div>
|
|
679
|
-
|
|
680
|
-
<
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
1255
|
+
{canShowFeedback(message) ? (
|
|
1256
|
+
<div style={styles.feedbackRow}>
|
|
1257
|
+
<button
|
|
1258
|
+
className="sh-feedback-btn"
|
|
1259
|
+
onClick={(event) =>
|
|
1260
|
+
handleFeedback(
|
|
1261
|
+
message.id,
|
|
1262
|
+
message.content,
|
|
1263
|
+
"upvote"
|
|
1264
|
+
)
|
|
1265
|
+
}
|
|
1266
|
+
style={styles.feedbackButton}
|
|
1267
|
+
>
|
|
1268
|
+
<ThumbsUpIcon
|
|
1269
|
+
fill={
|
|
1270
|
+
message.feedback === "upvote"
|
|
1271
|
+
? themeObj().actionColor || "#2563eb"
|
|
1272
|
+
: "none"
|
|
1273
|
+
}
|
|
1274
|
+
stroke={
|
|
1275
|
+
message.feedback === "upvote"
|
|
1276
|
+
? themeObj().actionColor || "#2563eb"
|
|
1277
|
+
: "currentColor"
|
|
1278
|
+
}
|
|
1279
|
+
/>
|
|
1280
|
+
</button>
|
|
1281
|
+
<button
|
|
1282
|
+
className="sh-feedback-btn"
|
|
1283
|
+
onClick={(event) =>
|
|
1284
|
+
handleFeedback(
|
|
1285
|
+
message.id,
|
|
1286
|
+
message.content,
|
|
1287
|
+
"downvote"
|
|
1288
|
+
)
|
|
1289
|
+
}
|
|
1290
|
+
style={styles.feedbackButton}
|
|
1291
|
+
>
|
|
1292
|
+
<ThumbsDownIcon
|
|
1293
|
+
fill={
|
|
1294
|
+
message.feedback === "downvote"
|
|
1295
|
+
? themeObj().actionColor || "#2563eb"
|
|
1296
|
+
: "none"
|
|
1297
|
+
}
|
|
1298
|
+
stroke={
|
|
1299
|
+
message.feedback === "downvote"
|
|
1300
|
+
? themeObj().actionColor || "#2563eb"
|
|
1301
|
+
: "currentColor"
|
|
1302
|
+
}
|
|
1303
|
+
/>
|
|
1304
|
+
</button>
|
|
1305
|
+
</div>
|
|
1306
|
+
) : null}
|
|
1307
|
+
{getShowProducts(message) ? (
|
|
1308
|
+
<ProductCardList
|
|
1309
|
+
skus={message.productSkus}
|
|
1310
|
+
defaultLocale={props.defaultLocale}
|
|
1311
|
+
showPriceIfEmpty={showPriceIfEmptyVal()}
|
|
1312
|
+
visibleFields={visibleFieldsList()}
|
|
1313
|
+
/>
|
|
1314
|
+
) : null}
|
|
688
1315
|
</div>
|
|
689
|
-
)
|
|
1316
|
+
) : null}
|
|
690
1317
|
</div>
|
|
691
|
-
)
|
|
1318
|
+
))}
|
|
692
1319
|
</div>
|
|
693
|
-
)
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
</div>
|
|
700
|
-
<div style={styles.inputSection}>
|
|
701
|
-
<div style={styles.inputWrapper}>
|
|
702
|
-
<input
|
|
703
|
-
type="text"
|
|
704
|
-
style={styles.input}
|
|
705
|
-
placeholder={TRANSLATIONS.askMeAnything}
|
|
706
|
-
value={input}
|
|
707
|
-
onInput={(e) => onInputChange(e)}
|
|
708
|
-
onKeyDown={(e) => onInputKeyDown(e)}
|
|
709
|
-
/>
|
|
710
|
-
<button
|
|
711
|
-
onClick={(e) => handleSend()}
|
|
1320
|
+
) : null}
|
|
1321
|
+
{error ? (
|
|
1322
|
+
<div style={styles.errorContainer}>Error: {error}</div>
|
|
1323
|
+
) : null}
|
|
1324
|
+
</div>
|
|
1325
|
+
<div
|
|
712
1326
|
style={{
|
|
713
|
-
...styles.
|
|
714
|
-
|
|
1327
|
+
...styles.inputSection,
|
|
1328
|
+
backgroundColor:
|
|
1329
|
+
themeObj().mainBackgroundColor ||
|
|
1330
|
+
styles.inputSection.backgroundColor,
|
|
715
1331
|
}}
|
|
716
1332
|
>
|
|
717
|
-
<
|
|
718
|
-
|
|
1333
|
+
<div style={styles.inputWrapper}>
|
|
1334
|
+
<input
|
|
1335
|
+
id="shop-prompter-input"
|
|
1336
|
+
type="text"
|
|
1337
|
+
style={styles.input}
|
|
1338
|
+
placeholder={
|
|
1339
|
+
agentExperience?.hintText || TRANSLATIONS.askMeAnything
|
|
1340
|
+
}
|
|
1341
|
+
value={input}
|
|
1342
|
+
onInput={(e) => onInputChange(e)}
|
|
1343
|
+
onKeyDown={(e) => onInputKeyDown(e)}
|
|
1344
|
+
/>
|
|
1345
|
+
<button
|
|
1346
|
+
onClick={(e) => handleSend()}
|
|
1347
|
+
style={{
|
|
1348
|
+
...styles.formButton,
|
|
1349
|
+
...styles.sendButton,
|
|
1350
|
+
backgroundColor:
|
|
1351
|
+
themeObj().actionColor ||
|
|
1352
|
+
styles.sendButton.backgroundColor,
|
|
1353
|
+
}}
|
|
1354
|
+
>
|
|
1355
|
+
<img
|
|
1356
|
+
alt="Send"
|
|
1357
|
+
src={ICONS.sendHorizontal}
|
|
1358
|
+
style={{
|
|
1359
|
+
padding: "4px",
|
|
1360
|
+
}}
|
|
1361
|
+
/>
|
|
1362
|
+
</button>
|
|
1363
|
+
</div>
|
|
1364
|
+
<p style={styles.disclaimer}>AI content may be inaccurate.</p>
|
|
1365
|
+
</div>
|
|
719
1366
|
</div>
|
|
720
|
-
|
|
721
|
-
</div>
|
|
1367
|
+
) : null}
|
|
722
1368
|
</div>
|
|
723
1369
|
) : null}
|
|
724
1370
|
</div>
|