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