@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/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  // src/shop-prompter.component.jsx
2
- import * as React from "react";
3
- import { useState, useEffect } from "react";
2
+ import * as React4 from "react";
3
+ import { useState as useState2, useEffect as useEffect2 } from "react";
4
+ import { marked } from "marked";
4
5
 
5
6
  // src/api/shop-prompter-api.ts
6
7
  var DefaultShopPrompterApi = class {
@@ -10,16 +11,27 @@ var DefaultShopPrompterApi = class {
10
11
  setApiConfig(config) {
11
12
  this.config = config;
12
13
  }
14
+ getHeaders() {
15
+ if (!this.config) {
16
+ return { "Content-Type": "application/json" };
17
+ }
18
+ const headers = {
19
+ "Content-Type": "application/json"
20
+ };
21
+ if (this.config.shopPrompterToken) {
22
+ headers["Authorization"] = `Bearer ${this.config.shopPrompterToken}`;
23
+ } else if (this.config.apiKey) {
24
+ headers["X-Api-Key"] = this.config.apiKey;
25
+ }
26
+ return headers;
27
+ }
13
28
  async execute(prompt, userId, sessionId) {
14
29
  if (!this.config) {
15
30
  throw new Error("API configuration not set. Call setApiConfig first.");
16
31
  }
17
32
  const response = await fetch(`${this.config.baseUrl}/interaction`, {
18
33
  method: "POST",
19
- headers: {
20
- "Content-Type": "application/json",
21
- "X-Api-Key": this.config.apiKey
22
- },
34
+ headers: this.getHeaders(),
23
35
  body: JSON.stringify({
24
36
  prompt,
25
37
  userId,
@@ -37,20 +49,12 @@ var DefaultShopPrompterApi = class {
37
49
  throw new Error("API configuration not set. Call setApiConfig first.");
38
50
  }
39
51
  const url = `${this.config.baseUrl}/interaction/stream`;
40
- console.log("ShopPrompter Request:", {
41
- url,
42
- prompt,
43
- userId,
44
- sessionId,
45
- cartContext
46
- });
47
52
  let response;
48
53
  try {
49
54
  response = await fetch(url, {
50
55
  method: "POST",
51
56
  headers: {
52
- "Content-Type": "application/json",
53
- "X-Api-Key": this.config.apiKey,
57
+ ...this.getHeaders(),
54
58
  Accept: "text/event-stream",
55
59
  "Cache-Control": "no-cache"
56
60
  },
@@ -69,7 +73,6 @@ var DefaultShopPrompterApi = class {
69
73
  });
70
74
  return;
71
75
  }
72
- console.log("ShopPrompter Response:", response.status);
73
76
  if (!response.ok) {
74
77
  const errorText = await response.text().catch(() => "");
75
78
  console.error("ShopPrompter API Error:", response.status, errorText);
@@ -90,21 +93,17 @@ var DefaultShopPrompterApi = class {
90
93
  while (true) {
91
94
  const { done, value } = await reader.read();
92
95
  if (done) {
93
- console.log("ShopPrompter Stream done");
94
96
  onEvent({ type: "close" });
95
97
  break;
96
98
  }
97
99
  const chunk = decoder.decode(value, { stream: true });
98
- console.log("ShopPrompter Raw chunk:", chunk);
99
100
  buffer += chunk;
100
101
  const lines = buffer.split("\n");
101
102
  buffer = lines.pop() || "";
102
103
  let currentEventType = "";
103
104
  for (const line of lines) {
104
- console.log("ShopPrompter Line:", line);
105
105
  if (line.startsWith("event:")) {
106
106
  currentEventType = line.slice(6).trim();
107
- console.log("ShopPrompter Event type:", currentEventType);
108
107
  if (currentEventType === "error") {
109
108
  onEvent({
110
109
  type: "error",
@@ -113,7 +112,6 @@ var DefaultShopPrompterApi = class {
113
112
  }
114
113
  } else if (line.startsWith("data:")) {
115
114
  const data = line.slice(5).trim();
116
- console.log("ShopPrompter Data:", data);
117
115
  if (data) {
118
116
  if (currentEventType === "error") {
119
117
  try {
@@ -130,7 +128,6 @@ var DefaultShopPrompterApi = class {
130
128
  }
131
129
  } else {
132
130
  const event = this.parseEvent(data);
133
- console.log("ShopPrompter Parsed event:", event);
134
131
  if (event) {
135
132
  onEvent(event);
136
133
  }
@@ -156,26 +153,47 @@ var DefaultShopPrompterApi = class {
156
153
  try {
157
154
  const response = await fetch(`${this.config.baseUrl}/agent-experience`, {
158
155
  method: "GET",
159
- headers: {
160
- "Content-Type": "application/json",
161
- "X-Api-Key": this.config.apiKey
162
- }
156
+ headers: this.getHeaders()
163
157
  });
164
158
  if (!response.ok) {
165
159
  console.error(`Failed to fetch agent experience: ${response.status}`);
166
160
  return null;
167
161
  }
168
162
  const data = await response.json();
169
- console.log(
170
- "## ~ DefaultShopPrompterApi ~ getAgentExperience ~ data:",
171
- data
172
- );
173
163
  return data;
174
164
  } catch (error) {
175
165
  console.error("Error fetching agent experience:", error);
176
166
  return null;
177
167
  }
178
168
  }
169
+ async sendFeedback(threadId, message, feedback) {
170
+ if (!this.config) {
171
+ throw new Error("API configuration not set. Call setApiConfig first.");
172
+ }
173
+ try {
174
+ const response = await fetch(`${this.config.baseUrl}/feedback`, {
175
+ method: "POST",
176
+ headers: this.getHeaders(),
177
+ body: JSON.stringify({
178
+ threadId,
179
+ message,
180
+ feedback
181
+ })
182
+ });
183
+ if (!response.ok) {
184
+ throw new Error(
185
+ "We are sorry, but we could not process your feedback. Please try again later."
186
+ );
187
+ }
188
+ } catch (error) {
189
+ if (error instanceof Error && error.message.startsWith("We are sorry")) {
190
+ throw error;
191
+ }
192
+ throw new Error(
193
+ "We are sorry, but we could not process your feedback. Please try again later."
194
+ );
195
+ }
196
+ }
179
197
  parseEvent(data) {
180
198
  try {
181
199
  const json = JSON.parse(data);
@@ -285,10 +303,78 @@ var DefaultShopPrompterApi = class {
285
303
  };
286
304
  var shopPrompterApi = new DefaultShopPrompterApi();
287
305
 
306
+ // src/api/product-api.ts
307
+ var DefaultProductApi = class {
308
+ constructor() {
309
+ this.config = null;
310
+ this.cache = /* @__PURE__ */ new Map();
311
+ }
312
+ setApiConfig(config) {
313
+ this.config = config;
314
+ }
315
+ isCached(skus) {
316
+ if (!skus || skus.length === 0) return true;
317
+ return skus.every((sku) => this.cache.has(sku));
318
+ }
319
+ getCached(skus) {
320
+ if (!skus || skus.length === 0) return [];
321
+ return skus.map((sku) => this.cache.get(sku)).filter(Boolean);
322
+ }
323
+ async getProducts(skus) {
324
+ if (!this.config) {
325
+ throw new Error("API configuration not set. Call setApiConfig first.");
326
+ }
327
+ const cachedProducts = [];
328
+ const missingSkus = [];
329
+ for (const sku of skus) {
330
+ if (this.cache.has(sku)) {
331
+ const cachedVal = this.cache.get(sku);
332
+ if (cachedVal) {
333
+ cachedProducts.push(cachedVal);
334
+ }
335
+ } else {
336
+ missingSkus.push(sku);
337
+ }
338
+ }
339
+ if (missingSkus.length === 0) {
340
+ return skus.map((sku) => this.cache.get(sku)).filter(Boolean);
341
+ }
342
+ const baseUrl = this.config.productsBaseUrl || this.config.baseUrl;
343
+ const url = `${baseUrl}/products?skus=${encodeURIComponent(missingSkus.join(","))}`;
344
+ const headers = {
345
+ "Content-Type": "application/json"
346
+ };
347
+ const response = await fetch(url, {
348
+ method: "GET",
349
+ headers
350
+ });
351
+ if (!response.ok) {
352
+ throw new Error(`Product API error: ${response.status}`);
353
+ }
354
+ const newProducts = await response.json();
355
+ const returnedSkus = /* @__PURE__ */ new Set();
356
+ for (const p of newProducts) {
357
+ if (p.sku) {
358
+ this.cache.set(p.sku, p);
359
+ returnedSkus.add(p.sku);
360
+ }
361
+ }
362
+ for (const sku of missingSkus) {
363
+ if (!returnedSkus.has(sku)) {
364
+ this.cache.set(sku, null);
365
+ }
366
+ }
367
+ return skus.map((sku) => this.cache.get(sku)).filter(Boolean);
368
+ }
369
+ };
370
+ var productApi = new DefaultProductApi();
371
+
288
372
  // src/api/session-handler.ts
289
373
  import { v4 as uuidv4 } from "uuid";
290
374
  var SESSION_KEY = "shopprompter_sessionId";
291
375
  var USER_KEY = "shopprompter_userId";
376
+ var SESSIONS_KEY = "shopprompter_sessions";
377
+ var MAX_SESSIONS = 3;
292
378
  var DefaultSessionHandler = class {
293
379
  constructor() {
294
380
  this.sessionId = "";
@@ -316,6 +402,98 @@ var DefaultSessionHandler = class {
316
402
  }
317
403
  return this.userId;
318
404
  }
405
+ // -------------------------------------------------------------------------
406
+ // Message persistence
407
+ // -------------------------------------------------------------------------
408
+ /** Persist a user message immediately when it is sent. */
409
+ saveUserMessage(sessionId, message) {
410
+ try {
411
+ const store = this.loadSessionStore();
412
+ if (!store[sessionId]) {
413
+ this.evictIfNeeded(store);
414
+ store[sessionId] = { createdAt: Date.now(), messages: [] };
415
+ }
416
+ store[sessionId].messages.push(message);
417
+ this.saveSessionStore(store);
418
+ } catch {
419
+ }
420
+ }
421
+ /**
422
+ * Persist the fully-streamed assistant message.
423
+ * If the message ID already exists in the store (shouldn't normally happen)
424
+ * it is replaced; otherwise it is appended.
425
+ */
426
+ saveAssistantMessage(sessionId, message) {
427
+ try {
428
+ const store = this.loadSessionStore();
429
+ if (!store[sessionId]) {
430
+ store[sessionId] = { createdAt: Date.now(), messages: [] };
431
+ }
432
+ const msgs = store[sessionId].messages;
433
+ const existingIdx = msgs.findIndex((m) => m.id === message.id);
434
+ if (existingIdx !== -1) {
435
+ msgs[existingIdx] = message;
436
+ } else {
437
+ msgs.push(message);
438
+ }
439
+ this.saveSessionStore(store);
440
+ } catch {
441
+ }
442
+ }
443
+ /** Return the persisted messages for the given session (newest first order preserved). */
444
+ loadMessages(sessionId) {
445
+ var _a, _b;
446
+ try {
447
+ const store = this.loadSessionStore();
448
+ return (_b = (_a = store[sessionId]) == null ? void 0 : _a.messages) != null ? _b : [];
449
+ } catch {
450
+ return [];
451
+ }
452
+ }
453
+ /** Update the feedback field of a specific persisted message. */
454
+ updateMessageFeedback(sessionId, messageId, feedback) {
455
+ try {
456
+ const store = this.loadSessionStore();
457
+ const session = store[sessionId];
458
+ if (!session) return;
459
+ const msg = session.messages.find((m) => m.id === messageId);
460
+ if (!msg) return;
461
+ msg.feedback = feedback;
462
+ this.saveSessionStore(store);
463
+ } catch {
464
+ }
465
+ }
466
+ // -------------------------------------------------------------------------
467
+ // Private helpers
468
+ // -------------------------------------------------------------------------
469
+ /**
470
+ * Remove the single oldest session from the store when it already holds
471
+ * MAX_SESSIONS entries. Mutates the store object in place.
472
+ */
473
+ evictIfNeeded(store) {
474
+ const sessionIds = Object.keys(store);
475
+ if (sessionIds.length < MAX_SESSIONS) return;
476
+ let oldestId = sessionIds[0];
477
+ let oldestTime = store[oldestId].createdAt;
478
+ for (const id of sessionIds) {
479
+ if (store[id].createdAt < oldestTime) {
480
+ oldestId = id;
481
+ oldestTime = store[id].createdAt;
482
+ }
483
+ }
484
+ delete store[oldestId];
485
+ }
486
+ loadSessionStore() {
487
+ try {
488
+ const raw = localStorage.getItem(SESSIONS_KEY);
489
+ return raw ? JSON.parse(raw) : {};
490
+ } catch {
491
+ return {};
492
+ }
493
+ }
494
+ saveSessionStore(store) {
495
+ localStorage.setItem(SESSIONS_KEY, JSON.stringify(store));
496
+ }
319
497
  getPersistedSessionId() {
320
498
  try {
321
499
  return localStorage.getItem(SESSION_KEY);
@@ -346,16 +524,13 @@ var DefaultSessionHandler = class {
346
524
  var sessionHandler = new DefaultSessionHandler();
347
525
 
348
526
  // src/shop-prompter.service.ts
349
- var SHOP_PROMPTER_CONFIG = {
350
- baseUrl: "https://demo.dev.shop-prompter.com/touch-points-api",
351
- apiKey: "864c87266ef52c079c09b3248d86b4b5ef430bf9e5a4188476124c93ee2f6dda380f337986837b30b60f73e6aceefe7a0e0f778b3d21a7fa7698cf8546afc709"
352
- };
353
527
  var ShopPrompterService = class {
354
- constructor() {
528
+ constructor(apiConfig) {
355
529
  this.isLoading = false;
356
530
  this.error = null;
357
531
  this.streamingText = "";
358
- shopPrompterApi.setApiConfig(SHOP_PROMPTER_CONFIG);
532
+ shopPrompterApi.setApiConfig(apiConfig);
533
+ productApi.setApiConfig(apiConfig);
359
534
  sessionHandler.initialize();
360
535
  }
361
536
  async sendMessage(prompt, callbacks, cartContext) {
@@ -366,7 +541,16 @@ var ShopPrompterService = class {
366
541
  this.streamingText = "";
367
542
  const userId = sessionHandler.getUserId();
368
543
  const sessionId = sessionHandler.getSessionId();
544
+ const userMsgId = Date.now().toString() + "-user";
545
+ sessionHandler.saveUserMessage(sessionId, {
546
+ id: userMsgId,
547
+ role: "user",
548
+ content: prompt,
549
+ productSkus: []
550
+ });
551
+ const assistantMsgId = Date.now().toString() + "-assistant";
369
552
  let accumulatedText = "";
553
+ let accumulatedSkus = [];
370
554
  try {
371
555
  await shopPrompterApi.executeStream(
372
556
  prompt,
@@ -381,6 +565,7 @@ var ShopPrompterService = class {
381
565
  (_a2 = callbacks.onTextUpdate) == null ? void 0 : _a2.call(callbacks, accumulatedText);
382
566
  break;
383
567
  case "productSkus":
568
+ accumulatedSkus = event.skus;
384
569
  (_b2 = callbacks.onProductSkus) == null ? void 0 : _b2.call(callbacks, event.skus);
385
570
  break;
386
571
  case "navigation":
@@ -393,6 +578,12 @@ var ShopPrompterService = class {
393
578
  this.isLoading = false;
394
579
  (_d = callbacks.onLoadingChange) == null ? void 0 : _d.call(callbacks, false);
395
580
  (_e = callbacks.onComplete) == null ? void 0 : _e.call(callbacks);
581
+ sessionHandler.saveAssistantMessage(sessionId, {
582
+ id: assistantMsgId,
583
+ role: "assistant",
584
+ content: accumulatedText,
585
+ productSkus: accumulatedSkus
586
+ });
396
587
  break;
397
588
  case "error":
398
589
  this.error = event.reason;
@@ -414,9 +605,6 @@ var ShopPrompterService = class {
414
605
  return accumulatedText;
415
606
  }
416
607
  async getAgentExperience() {
417
- console.log(
418
- "## ~ ShopPrompterService ~ getAgentExperience ~ getAgentExperience:"
419
- );
420
608
  try {
421
609
  return await shopPrompterApi.getAgentExperience();
422
610
  } catch (err) {
@@ -424,6 +612,32 @@ var ShopPrompterService = class {
424
612
  throw err;
425
613
  }
426
614
  }
615
+ /**
616
+ * Load persisted chat messages for the current session from localStorage.
617
+ * Returns an empty array if nothing is stored yet.
618
+ */
619
+ loadMessages() {
620
+ const sessionId = sessionHandler.getSessionId();
621
+ const persisted = sessionHandler.loadMessages(sessionId);
622
+ return persisted.map((msg) => {
623
+ var _a, _b;
624
+ return {
625
+ id: msg.id,
626
+ role: msg.role,
627
+ content: msg.content,
628
+ productSkus: (_a = msg.productSkus) != null ? _a : [],
629
+ feedback: (_b = msg.feedback) != null ? _b : null
630
+ };
631
+ });
632
+ }
633
+ async sendFeedback(messageId, messageContent, feedback) {
634
+ const userId = sessionHandler.getUserId();
635
+ const sessionId = sessionHandler.getSessionId();
636
+ const threadId = `${userId}:${sessionId}`;
637
+ await shopPrompterApi.sendFeedback(threadId, messageContent, feedback);
638
+ const storedFeedback = feedback === "clear" ? null : feedback;
639
+ sessionHandler.updateMessageFeedback(sessionId, messageId, storedFeedback);
640
+ }
427
641
  resetSession() {
428
642
  sessionHandler.regenerate();
429
643
  }
@@ -436,14 +650,297 @@ var ShopPrompterService = class {
436
650
  }
437
651
  };
438
652
 
439
- // src/shop-prompter.component.jsx
440
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
653
+ // src/thumbs-up-icon.component.jsx
654
+ import * as React from "react";
655
+ import { jsx, jsxs } from "react/jsx-runtime";
656
+ function ThumbsUpIcon(props) {
657
+ return /* @__PURE__ */ jsxs(
658
+ "svg",
659
+ {
660
+ xmlns: "http://www.w3.org/2000/svg",
661
+ width: "18",
662
+ height: "18",
663
+ viewBox: "0 0 24 24",
664
+ "stroke-width": "2",
665
+ "stroke-linecap": "round",
666
+ "stroke-linejoin": "round",
667
+ fill: props.fill || "none",
668
+ stroke: props.stroke || "currentColor",
669
+ style: {
670
+ overflow: "visible"
671
+ },
672
+ children: [
673
+ /* @__PURE__ */ jsx("path", { d: "M7 10v12" }),
674
+ /* @__PURE__ */ jsx("path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z" })
675
+ ]
676
+ }
677
+ );
678
+ }
679
+ var thumbs_up_icon_component_default = ThumbsUpIcon;
680
+
681
+ // src/thumbs-down-icon.component.jsx
682
+ import * as React2 from "react";
683
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
684
+ function ThumbsDownIcon(props) {
685
+ return /* @__PURE__ */ jsxs2(
686
+ "svg",
687
+ {
688
+ xmlns: "http://www.w3.org/2000/svg",
689
+ width: "18",
690
+ height: "18",
691
+ viewBox: "0 0 24 24",
692
+ "stroke-width": "2",
693
+ "stroke-linecap": "round",
694
+ "stroke-linejoin": "round",
695
+ fill: props.fill || "none",
696
+ stroke: props.stroke || "currentColor",
697
+ style: {
698
+ overflow: "visible"
699
+ },
700
+ children: [
701
+ /* @__PURE__ */ jsx2("path", { d: "M17 14V2" }),
702
+ /* @__PURE__ */ jsx2("path", { d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z" })
703
+ ]
704
+ }
705
+ );
706
+ }
707
+ var thumbs_down_icon_component_default = ThumbsDownIcon;
708
+
709
+ // src/product-card-list.component.jsx
710
+ import * as React3 from "react";
711
+ import { useState, useEffect } from "react";
712
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
441
713
  var styles = {
714
+ productCardsContainer: {
715
+ marginTop: "0.75rem",
716
+ display: "flex",
717
+ gap: "0.75rem",
718
+ overflowX: "auto",
719
+ width: "100%",
720
+ paddingBottom: "0.5rem",
721
+ boxSizing: "border-box",
722
+ scrollbarWidth: "thin",
723
+ scrollSnapType: "x mandatory",
724
+ WebkitOverflowScrolling: "touch"
725
+ },
726
+ productCard: {
727
+ minWidth: "9.5rem",
728
+ maxWidth: "9.5rem",
729
+ backgroundColor: "white",
730
+ border: "1px solid #f3f4f6",
731
+ borderRadius: "0.75rem",
732
+ overflow: "hidden",
733
+ boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03)",
734
+ display: "flex",
735
+ flexDirection: "column",
736
+ scrollSnapAlign: "start"
737
+ },
738
+ productImageContainer: {
739
+ height: "7rem",
740
+ backgroundColor: "#f9fafb",
741
+ display: "flex",
742
+ alignItems: "center",
743
+ justifyContent: "center",
744
+ padding: "0.5rem",
745
+ borderBottom: "1px solid #f3f4f6"
746
+ },
747
+ productImage: {
748
+ maxHeight: "100%",
749
+ maxWidth: "100%",
750
+ objectFit: "contain"
751
+ },
752
+ productInfo: {
753
+ padding: "0.625rem",
754
+ display: "flex",
755
+ flexDirection: "column",
756
+ gap: "0.25rem"
757
+ },
758
+ productName: {
759
+ fontSize: "0.8125rem",
760
+ fontWeight: 600,
761
+ color: "#1f2937",
762
+ margin: 0,
763
+ whiteSpace: "nowrap",
764
+ overflow: "hidden",
765
+ textOverflow: "ellipsis"
766
+ },
767
+ productDynamicField: {
768
+ fontSize: "0.6875rem",
769
+ color: "#6b7280",
770
+ margin: 0,
771
+ whiteSpace: "nowrap",
772
+ overflow: "hidden",
773
+ textOverflow: "ellipsis"
774
+ },
775
+ productPrice: {
776
+ fontSize: "0.8125rem",
777
+ fontWeight: 500,
778
+ color: "#4b5563",
779
+ margin: 0
780
+ },
781
+ statusContainer: {
782
+ padding: "0.5rem 0",
783
+ fontSize: "0.75rem",
784
+ color: "#6b7280",
785
+ display: "flex",
786
+ alignItems: "center",
787
+ gap: "0.5rem"
788
+ },
789
+ errorText: {
790
+ color: "#ef4444"
791
+ },
792
+ spinner: {
793
+ color: "#6b7280"
794
+ },
795
+ wrapper: {
796
+ width: "100%",
797
+ maxWidth: "100%",
798
+ boxSizing: "border-box",
799
+ overflow: "hidden"
800
+ }
801
+ };
802
+ function ProductCardList(props) {
803
+ const [products, setProducts] = useState(() => []);
804
+ const [loading, setLoading] = useState(() => false);
805
+ const [error, setError] = useState(() => null);
806
+ function fetchProducts() {
807
+ let skusList = props.skus;
808
+ if (typeof skusList === "string") {
809
+ skusList = skusList.split(",").map((s) => s.trim()).filter(Boolean);
810
+ }
811
+ if (!skusList || skusList.length === 0) {
812
+ setProducts([]);
813
+ setLoading(false);
814
+ return;
815
+ }
816
+ if (productApi.isCached(skusList)) {
817
+ setProducts(productApi.getCached(skusList));
818
+ setLoading(false);
819
+ setError(null);
820
+ return;
821
+ }
822
+ setLoading(true);
823
+ setError(null);
824
+ productApi.getProducts(skusList).then((data) => {
825
+ setProducts(data || []);
826
+ setLoading(false);
827
+ }).catch((err) => {
828
+ console.error("Failed to fetch products:", err);
829
+ setError((err == null ? void 0 : err.message) || "Failed to load products");
830
+ setLoading(false);
831
+ });
832
+ }
833
+ function getProductName(product) {
834
+ var _a;
835
+ const locale = props.defaultLocale || "de";
836
+ const localized = ((_a = product.localization) == null ? void 0 : _a[locale]) || Object.values(product.localization || {})[0];
837
+ return (localized == null ? void 0 : localized.name) || product.sku;
838
+ }
839
+ function showPriceIfEmptyVal() {
840
+ const val = props.showPriceIfEmpty;
841
+ if (typeof val === "string") {
842
+ return val === "true";
843
+ }
844
+ return val != null ? val : false;
845
+ }
846
+ function visibleFieldsList() {
847
+ const val = props.visibleFields;
848
+ if (typeof val === "string") {
849
+ try {
850
+ return JSON.parse(val);
851
+ } catch (e) {
852
+ return val.split(",").map((s) => s.trim()).filter(Boolean);
853
+ }
854
+ }
855
+ return val || [];
856
+ }
857
+ function getDynamicField(product, field) {
858
+ var _a;
859
+ const locale = props.defaultLocale || "de";
860
+ const localized = ((_a = product.localization) == null ? void 0 : _a[locale]) || Object.values(product.localization || {})[0];
861
+ if (!localized) return void 0;
862
+ const parts = field.split(".");
863
+ let current = localized;
864
+ for (let i = 0; i < parts.length; i++) {
865
+ if (current === void 0 || current === null) return void 0;
866
+ current = current[parts[i]];
867
+ }
868
+ return current;
869
+ }
870
+ function getProductPrice(product) {
871
+ if (!product.pricing) return "";
872
+ const priceVal = product.pricing.gross;
873
+ const currency = product.pricing.currency;
874
+ if (priceVal === void 0 || priceVal === null) return "";
875
+ if (priceVal === 0 && !showPriceIfEmptyVal()) return "";
876
+ return priceVal.toFixed(2) + " " + (currency || "\u20AC");
877
+ }
878
+ function getProductImage(product) {
879
+ var _a;
880
+ return ((_a = product.images) == null ? void 0 : _a[0]) || "https://placehold.co/150x150?text=" + product.sku;
881
+ }
882
+ useEffect(() => {
883
+ fetchProducts();
884
+ }, []);
885
+ useEffect(() => {
886
+ fetchProducts();
887
+ }, [
888
+ props.skus ? Array.isArray(props.skus) ? props.skus.join(",") : props.skus : ""
889
+ ]);
890
+ return /* @__PURE__ */ jsx3(Fragment, { children: props.skus && props.skus.length > 0 ? /* @__PURE__ */ jsx3(Fragment, { children: /* @__PURE__ */ jsxs3("div", { style: styles.wrapper, children: [
891
+ loading ? /* @__PURE__ */ jsx3("div", { style: styles.statusContainer, children: /* @__PURE__ */ jsx3("span", { children: "Loading products..." }) }) : null,
892
+ !loading && error ? /* @__PURE__ */ jsx3("div", { style: styles.statusContainer, children: /* @__PURE__ */ jsxs3("span", { style: styles.errorText, children: [
893
+ "Error: ",
894
+ error
895
+ ] }) }) : null,
896
+ !loading && products && products.length > 0 ? /* @__PURE__ */ jsx3("div", { style: styles.productCardsContainer, children: products == null ? void 0 : products.map((product) => {
897
+ var _a;
898
+ return /* @__PURE__ */ jsxs3("div", { style: styles.productCard, children: [
899
+ /* @__PURE__ */ jsx3("div", { style: styles.productImageContainer, children: /* @__PURE__ */ jsx3(
900
+ "img",
901
+ {
902
+ src: getProductImage(product),
903
+ alt: getProductName(product),
904
+ style: styles.productImage
905
+ }
906
+ ) }),
907
+ /* @__PURE__ */ jsxs3("div", { style: styles.productInfo, children: [
908
+ /* @__PURE__ */ jsx3(
909
+ "p",
910
+ {
911
+ style: styles.productName,
912
+ title: getProductName(product),
913
+ children: getProductName(product)
914
+ }
915
+ ),
916
+ (_a = visibleFieldsList()) == null ? void 0 : _a.map(
917
+ (field) => getDynamicField(product, field) !== void 0 ? /* @__PURE__ */ jsx3(
918
+ "p",
919
+ {
920
+ style: styles.productDynamicField,
921
+ title: String(getDynamicField(product, field)),
922
+ children: String(getDynamicField(product, field))
923
+ }
924
+ ) : null
925
+ ),
926
+ getProductPrice(product) !== "" ? /* @__PURE__ */ jsx3("p", { style: styles.productPrice, children: getProductPrice(product) }) : null
927
+ ] })
928
+ ] }, product.sku);
929
+ }) }) : null
930
+ ] }) }) : null });
931
+ }
932
+ var product_card_list_component_default = ProductCardList;
933
+
934
+ // src/shop-prompter.component.jsx
935
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
936
+ var THINKING_SPINNER = "M21 12a9 9 0 1 1-6.219-8.56";
937
+ var styles2 = {
442
938
  header: {
443
939
  display: "flex",
444
940
  alignItems: "center",
445
941
  justifyContent: "space-between",
446
- padding: "16px"
942
+ padding: "16px",
943
+ borderBottom: "1px solid #e5e7eb"
447
944
  },
448
945
  subHeaderContainer: {
449
946
  display: "flex",
@@ -459,6 +956,7 @@ var styles = {
459
956
  border: "none",
460
957
  cursor: "pointer",
461
958
  transition: "background-color 0.2s, color 0.2s",
959
+ fontFamily: "inherit",
462
960
  onHover: {
463
961
  backgroundColor: "hsl(220 14% 96%)",
464
962
  color: "hsl(220 13% 13%)"
@@ -479,7 +977,8 @@ var styles = {
479
977
  gap: "0.5rem",
480
978
  cursor: "pointer",
481
979
  fontSize: "0.875rem",
482
- color: "#09090b"
980
+ color: "#09090b",
981
+ fontFamily: "inherit"
483
982
  },
484
983
  ButtonSheetButton: {
485
984
  color: "#6b7280",
@@ -488,11 +987,13 @@ var styles = {
488
987
  cursor: "pointer",
489
988
  padding: "0.25rem",
490
989
  fontSize: "1.25rem",
491
- transition: "color 0.2s"
990
+ transition: "color 0.2s",
991
+ fontFamily: "inherit"
492
992
  },
493
993
  chatContainer: {
494
994
  flex: 1,
495
995
  overflowY: "auto",
996
+ overflowX: "hidden",
496
997
  padding: "1rem",
497
998
  backgroundColor: "white"
498
999
  },
@@ -538,12 +1039,17 @@ var styles = {
538
1039
  messageContainerUser: {
539
1040
  display: "flex",
540
1041
  flexDirection: "column",
541
- alignItems: "flex-end"
1042
+ alignItems: "flex-end",
1043
+ marginBottom: "8px"
542
1044
  },
543
1045
  messageContainerAssistant: {
544
1046
  display: "flex",
545
1047
  flexDirection: "column",
546
- alignItems: "flex-start"
1048
+ alignItems: "flex-start",
1049
+ marginBottom: "8px",
1050
+ width: "100%",
1051
+ maxWidth: "100%",
1052
+ boxSizing: "border-box"
547
1053
  },
548
1054
  messageBubbleUser: {
549
1055
  backgroundColor: "#111827",
@@ -553,7 +1059,8 @@ var styles = {
553
1059
  padding: "0.5rem 1rem",
554
1060
  fontSize: "0.875rem",
555
1061
  boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
556
- maxWidth: "85%"
1062
+ maxWidth: "85%",
1063
+ textAlign: "left"
557
1064
  },
558
1065
  messageBubbleAssistant: {
559
1066
  backgroundColor: "#f3f4f6",
@@ -563,7 +1070,8 @@ var styles = {
563
1070
  padding: "0.5rem 1rem",
564
1071
  fontSize: "0.875rem",
565
1072
  boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
566
- maxWidth: "85%"
1073
+ maxWidth: "85%",
1074
+ textAlign: "left"
567
1075
  },
568
1076
  thinkingIndicator: {
569
1077
  display: "flex",
@@ -645,7 +1153,8 @@ var styles = {
645
1153
  outline: "none",
646
1154
  fontSize: "0.875rem",
647
1155
  color: "#111827",
648
- padding: "0.25rem 0"
1156
+ padding: "0.25rem 0",
1157
+ fontFamily: "inherit"
649
1158
  },
650
1159
  formButton: {
651
1160
  backgroundColor: "transparent",
@@ -658,7 +1167,8 @@ var styles = {
658
1167
  fontWeight: "bold",
659
1168
  border: "none",
660
1169
  cursor: "pointer",
661
- transition: "background-color 0.2s"
1170
+ transition: "background-color 0.2s",
1171
+ fontFamily: "inherit"
662
1172
  },
663
1173
  sendButton: {
664
1174
  backgroundColor: "#AD59FF1A"
@@ -668,90 +1178,297 @@ var styles = {
668
1178
  color: "#9ca3af",
669
1179
  textAlign: "center",
670
1180
  marginTop: "0.75rem"
1181
+ },
1182
+ backdrop: {
1183
+ position: "fixed",
1184
+ top: 0,
1185
+ left: 0,
1186
+ right: 0,
1187
+ bottom: 0,
1188
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
1189
+ backdropFilter: "blur(4px)",
1190
+ zIndex: 1e3
1191
+ },
1192
+ feedbackRow: {
1193
+ display: "flex",
1194
+ alignItems: "center",
1195
+ gap: "0.5rem",
1196
+ marginTop: "0.5rem",
1197
+ marginLeft: "0.75rem"
1198
+ },
1199
+ feedbackButton: {
1200
+ backgroundColor: "transparent",
1201
+ border: "none",
1202
+ cursor: "pointer",
1203
+ padding: "6px",
1204
+ borderRadius: "6px",
1205
+ display: "flex",
1206
+ alignItems: "center",
1207
+ justifyContent: "center",
1208
+ transition: "background-color 0.2s"
1209
+ },
1210
+ warningBanner: {
1211
+ backgroundColor: "#fffbeb",
1212
+ color: "#b45309",
1213
+ border: "1px solid #fde68a",
1214
+ borderRadius: "0.375rem",
1215
+ padding: "0.25rem 0.5rem",
1216
+ fontSize: "0.6875rem",
1217
+ fontWeight: 500,
1218
+ textAlign: "center",
1219
+ margin: "0 0.5rem",
1220
+ flex: 1,
1221
+ display: "flex",
1222
+ alignItems: "center",
1223
+ justifyContent: "center"
1224
+ },
1225
+ insufficientConfigContainer: {
1226
+ flex: 1,
1227
+ display: "flex",
1228
+ flexDirection: "column",
1229
+ alignItems: "center",
1230
+ justifyContent: "center",
1231
+ padding: "2rem",
1232
+ textAlign: "center",
1233
+ backgroundColor: "#fff5f5",
1234
+ color: "#2d3748"
1235
+ },
1236
+ insufficientConfigIconContainer: {
1237
+ backgroundColor: "#fee2e2",
1238
+ padding: "1rem",
1239
+ borderRadius: "50%",
1240
+ marginBottom: "1rem",
1241
+ display: "flex",
1242
+ alignItems: "center",
1243
+ justifyContent: "center",
1244
+ boxShadow: "0 4px 6px -1px rgba(239, 68, 68, 0.1), 0 2px 4px -1px rgba(239, 68, 68, 0.06)"
1245
+ },
1246
+ insufficientConfigTitle: {
1247
+ fontSize: "1.25rem",
1248
+ fontWeight: 700,
1249
+ color: "#991b1b",
1250
+ marginBottom: "0.5rem"
1251
+ },
1252
+ insufficientConfigMessage: {
1253
+ fontSize: "0.875rem",
1254
+ color: "#7f1d1d",
1255
+ marginBottom: "1.5rem",
1256
+ lineHeight: "1.5",
1257
+ maxWidth: "280px"
1258
+ },
1259
+ insufficientConfigDetails: {
1260
+ backgroundColor: "white",
1261
+ border: "1px solid #fee2e2",
1262
+ borderRadius: "0.5rem",
1263
+ padding: "1rem",
1264
+ textAlign: "left",
1265
+ width: "100%",
1266
+ maxWidth: "300px",
1267
+ boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.05)"
671
1268
  }
672
1269
  };
1270
+ var ANIMATION_STYLES = `
1271
+ @keyframes sh-fade-in {
1272
+ from {
1273
+ opacity: 0;
1274
+ transform: translate(-50%, -48%) scale(0.96);
1275
+ }
1276
+ to {
1277
+ opacity: 1;
1278
+ transform: translate(-50%, -50%) scale(1);
1279
+ }
1280
+ }
1281
+ @keyframes sh-fade-out {
1282
+ from {
1283
+ opacity: 1;
1284
+ transform: translate(-50%, -50%) scale(1);
1285
+ }
1286
+ to {
1287
+ opacity: 0;
1288
+ transform: translate(-50%, -48%) scale(0.96);
1289
+ }
1290
+ }
1291
+ @keyframes sh-backdrop-fade-in {
1292
+ from {
1293
+ opacity: 0;
1294
+ }
1295
+ to {
1296
+ opacity: 1;
1297
+ }
1298
+ }
1299
+ @keyframes sh-backdrop-fade-out {
1300
+ from {
1301
+ opacity: 1;
1302
+ }
1303
+ to {
1304
+ opacity: 0;
1305
+ }
1306
+ }
1307
+ .sh-dialog-animate {
1308
+ animation: sh-fade-in 0.22s cubic-bezier(0.16, 1, 0.3, 1) forwards;
1309
+ }
1310
+ .sh-dialog-animate-out {
1311
+ animation: sh-fade-out 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
1312
+ }
1313
+ .sh-backdrop-animate {
1314
+ animation: sh-backdrop-fade-in 0.18s ease-out forwards;
1315
+ }
1316
+ .sh-backdrop-animate-out {
1317
+ animation: sh-backdrop-fade-out 0.18s ease-out forwards;
1318
+ }
1319
+ .sh-feedback-btn {
1320
+ color: #a1a1aa;
1321
+ border-radius: 4px;
1322
+ transition: color 0.2s, background-color 0.2s;
1323
+ }
1324
+ .sh-feedback-btn:hover {
1325
+ background-color: #f4f4f5 !important;
1326
+ color: #3f3f46 !important;
1327
+ }
1328
+ .sh-header-btn {
1329
+ transition: all 0.2s;
1330
+ }
1331
+ .sh-header-btn:hover {
1332
+ background-color: #f9fafb !important;
1333
+ border-color: #d1d5db !important;
1334
+ }
1335
+ `;
673
1336
  var TRANSLATIONS = {
674
1337
  newChat: "New Chat",
675
1338
  welcomeToShopPrompter: "Welcome to ShopPrompter",
676
1339
  welcomeDescription: "I am your personal AI shopping assistant. Ask me anything about our products!",
677
1340
  askMeAnything: "Ask me anything...",
678
1341
  thinking: "Thinking...",
679
- showPopularItems: "Show popular items",
680
- compareProducts: "Compare products",
681
- findByBudget: "Find by budget"
1342
+ feedbackError: "We are sorry, but we could not process your feedback. Please try again later."
682
1343
  };
683
1344
  var ICONS = {
684
1345
  chat: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/message-square.svg",
685
1346
  shopprompter: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/bot.svg",
686
1347
  popularitems: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/fire.svg",
687
1348
  compareproducts: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/box.svg",
688
- findbybudget: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/foto.svg",
689
1349
  sendHorizontal: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/send-horizontal.svg"
690
1350
  };
691
1351
  function ShopPrompter(props) {
692
- var _a, _b, _c;
693
- const [input, setInput] = useState(() => "");
694
- const [isLoading, setIsLoading] = useState(() => false);
695
- const [error, setError] = useState(() => null);
696
- const [chatMessages, setChatMessages] = useState(() => []);
697
- const [showChat, setShowChat] = useState(
698
- () => props.chatPosition === "right-panel" || props.chatPosition === "full-page"
1352
+ var _a, _b, _c, _d;
1353
+ const [input, setInput] = useState2(() => "");
1354
+ const [isLoading, setIsLoading] = useState2(() => false);
1355
+ const [error, setError] = useState2(() => null);
1356
+ const [chatMessages, setChatMessages] = useState2(() => []);
1357
+ const [showChat, setShowChat] = useState2(() => false);
1358
+ const [isClosing, setIsClosing] = useState2(() => false);
1359
+ const [closeTimeout, setCloseTimeout] = useState2(() => null);
1360
+ const [service, setService] = useState2(() => null);
1361
+ const [agentExperience, setAgentExperience] = useState2(() => null);
1362
+ const [animationClass, setAnimationClass] = useState2(() => "");
1363
+ const [backdropAnimationClass, setBackdropAnimationClass] = useState2(
1364
+ () => ""
699
1365
  );
700
- const [service, setService] = useState(() => null);
701
- const [isHeaderButtonHovered, setIsHeaderButtonHovered] = useState(
702
- () => false
703
- );
704
- const [agentExperience, setAgentExperience] = useState(() => null);
1366
+ function hasToken() {
1367
+ var _a2;
1368
+ const token = props.shopPrompterToken || ((_a2 = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a2.shopPrompterToken);
1369
+ return !!token;
1370
+ }
1371
+ function isConfigInsufficient() {
1372
+ var _a2, _b2;
1373
+ const token = props.shopPrompterToken || ((_a2 = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a2.shopPrompterToken);
1374
+ const apiKey = (_b2 = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _b2.apiKey;
1375
+ return !token && !apiKey;
1376
+ }
1377
+ function showPriceIfEmptyVal() {
1378
+ const val = props.showPriceIfEmpty;
1379
+ if (typeof val === "string") {
1380
+ return val === "true";
1381
+ }
1382
+ return val != null ? val : false;
1383
+ }
1384
+ function visibleFieldsList() {
1385
+ const val = props.visibleFields;
1386
+ if (typeof val === "string") {
1387
+ try {
1388
+ return JSON.parse(val);
1389
+ } catch (e) {
1390
+ return val.split(",").map((s) => s.trim()).filter(Boolean);
1391
+ }
1392
+ }
1393
+ return val || [];
1394
+ }
1395
+ function themeObj() {
1396
+ if (typeof props.theme === "string") {
1397
+ try {
1398
+ return JSON.parse(props.theme);
1399
+ } catch (e) {
1400
+ return {};
1401
+ }
1402
+ }
1403
+ return props.theme || {};
1404
+ }
1405
+ function prompts() {
1406
+ return (agentExperience == null ? void 0 : agentExperience.predefinedPrompts) || [];
1407
+ }
1408
+ function apiConfigObj() {
1409
+ if (typeof props.apiConfig === "string") {
1410
+ try {
1411
+ return JSON.parse(props.apiConfig);
1412
+ } catch (e) {
1413
+ return null;
1414
+ }
1415
+ }
1416
+ return props.apiConfig || null;
1417
+ }
705
1418
  function containerStyle() {
706
1419
  const pos = props.chatPosition || "classic-chatbot";
707
1420
  const isFull = pos === "full-page";
708
- const isBottom = pos === "bottom-sheet";
1421
+ const isDialog = pos === "dialog";
709
1422
  const isClassic = pos === "classic-chatbot";
710
1423
  const isRight = pos === "right-panel";
711
1424
  return {
712
1425
  position: isFull ? "relative" : "fixed",
713
- bottom: isClassic ? "1rem" : isBottom ? "2rem" : "0",
714
- right: isClassic || isRight ? "1rem" : "0",
715
- width: isFull ? "100%" : isBottom ? "90%" : "24rem",
716
- height: isClassic ? "550px" : isBottom ? "700px" : "100%",
717
- maxWidth: isBottom ? "900px" : "none",
718
- left: isBottom ? "50%" : "auto",
719
- transform: isBottom ? "translateX(-50%)" : "none",
720
- zIndex: 50,
721
- backgroundColor: "white",
1426
+ bottom: isClassic ? "1rem" : isDialog ? "auto" : "0",
1427
+ top: isDialog ? "50%" : "auto",
1428
+ right: isClassic || isRight ? "1rem" : isDialog ? "auto" : "0",
1429
+ left: isDialog ? "50%" : isClassic || isRight || isFull ? "auto" : "0",
1430
+ transform: isDialog ? "translate(-50%, -50%)" : "none",
1431
+ width: isFull ? "100%" : isDialog ? "90%" : "24rem",
1432
+ height: isClassic ? "550px" : isDialog ? "700px" : isFull ? "600px" : "100%",
1433
+ maxWidth: isDialog ? "900px" : "none",
1434
+ maxHeight: isDialog ? "90vh" : "none",
1435
+ zIndex: isDialog ? 1001 : isClassic || isRight ? 1001 : 50,
1436
+ backgroundColor: themeObj().mainBackgroundColor || "white",
722
1437
  display: "flex",
723
1438
  flexDirection: "column",
724
1439
  overflow: "hidden",
725
1440
  borderRadius: isFull ? "0" : "0.5rem",
726
1441
  border: isFull ? "none" : "1px solid #e5e7eb",
727
- boxShadow: isFull ? "none" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
1442
+ boxShadow: isFull ? "none" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
1443
+ fontFamily: themeObj().fontFamily || void 0
728
1444
  };
729
1445
  }
730
1446
  function containerClass() {
731
1447
  const pos = props.chatPosition || "classic-chatbot";
732
1448
  if (pos === "classic-chatbot") return "sh-classic";
733
1449
  if (pos === "right-panel") return "sh-right";
734
- if (pos === "bottom-sheet") return "sh-bottom";
1450
+ if (pos === "dialog") {
1451
+ return "sh-dialog " + animationClass;
1452
+ }
735
1453
  return "sh-full";
736
1454
  }
737
1455
  function messages() {
738
- return chatMessages.map((msg) => ({
739
- ...msg,
740
- safeProductSkus: msg.productSkus || []
741
- }));
1456
+ return chatMessages;
1457
+ }
1458
+ function parseMarkdown(content) {
1459
+ if (!content) return "";
1460
+ return String(marked.parse(content));
742
1461
  }
743
1462
  function showWelcome() {
744
1463
  return chatMessages.length === 0;
745
1464
  }
746
- function getProductImageUrl(sku) {
747
- return "https://placehold.co/100x100?text=" + sku;
1465
+ function getShowProducts(message) {
1466
+ return message.productSkus && message.productSkus.length > 0;
748
1467
  }
749
- function getProductLink(sku) {
750
- return "/product/" + sku;
751
- }
752
- function handleSend() {
753
- if (!input.trim() || isLoading) return;
754
- const userQuery = input;
1468
+ function handleSend(overrideQuery) {
1469
+ const actualQuery = overrideQuery || input;
1470
+ if (!actualQuery.trim() || isLoading) return;
1471
+ const userQuery = actualQuery;
755
1472
  setInput("");
756
1473
  const userMsg = {
757
1474
  id: Date.now().toString() + "-user",
@@ -759,30 +1476,45 @@ function ShopPrompter(props) {
759
1476
  content: userQuery,
760
1477
  productSkus: []
761
1478
  };
762
- setChatMessages([...chatMessages, userMsg]);
763
1479
  const assistantMsg = {
764
1480
  id: Date.now().toString() + "-assistant",
765
1481
  role: "assistant",
766
1482
  content: "",
767
1483
  productSkus: []
768
1484
  };
769
- setChatMessages([...chatMessages, assistantMsg]);
1485
+ let currentMessages = [...chatMessages, userMsg, assistantMsg];
1486
+ setChatMessages(currentMessages);
1487
+ setTimeout(() => {
1488
+ const inputEl = document.getElementById("shop-prompter-input");
1489
+ if (inputEl) {
1490
+ inputEl.value = "";
1491
+ inputEl.focus();
1492
+ }
1493
+ }, 0);
770
1494
  service == null ? void 0 : service.sendMessage(
771
1495
  userQuery,
772
1496
  {
773
1497
  onTextUpdate: (text) => {
774
- const updatedMessages = [...chatMessages];
1498
+ const updatedMessages = [...currentMessages];
775
1499
  const lastMsg = updatedMessages[updatedMessages.length - 1];
776
1500
  if (lastMsg) {
777
- lastMsg.content = text;
1501
+ updatedMessages[updatedMessages.length - 1] = {
1502
+ ...lastMsg,
1503
+ content: text
1504
+ };
1505
+ currentMessages = updatedMessages;
778
1506
  setChatMessages(updatedMessages);
779
1507
  }
780
1508
  },
781
1509
  onProductSkus: (skus) => {
782
- const updatedMessages = [...chatMessages];
1510
+ const updatedMessages = [...currentMessages];
783
1511
  const lastMsg = updatedMessages[updatedMessages.length - 1];
784
1512
  if (lastMsg) {
785
- lastMsg.productSkus = skus;
1513
+ updatedMessages[updatedMessages.length - 1] = {
1514
+ ...lastMsg,
1515
+ productSkus: skus
1516
+ };
1517
+ currentMessages = updatedMessages;
786
1518
  setChatMessages(updatedMessages);
787
1519
  }
788
1520
  },
@@ -796,29 +1528,63 @@ function ShopPrompter(props) {
796
1528
  if (props.onCartOperation) {
797
1529
  props.onCartOperation(ops);
798
1530
  }
1531
+ dispatchCartOperation(ops);
799
1532
  }
800
1533
  },
801
1534
  props.cart || []
802
1535
  );
803
1536
  }
1537
+ function dispatchCartOperation(ops) {
1538
+ if (typeof window !== "undefined") {
1539
+ const root = typeof self !== "undefined" && self && "dispatchEvent" in self && !(self instanceof Window) ? self : null;
1540
+ if (root) {
1541
+ root.dispatchEvent(
1542
+ new CustomEvent("cartOperation", {
1543
+ detail: ops
1544
+ })
1545
+ );
1546
+ }
1547
+ }
1548
+ }
804
1549
  function toggleChat() {
805
- setShowChat(!showChat);
806
- if (!showChat && props.onClose) {
807
- props.onClose();
1550
+ if (showChat) {
1551
+ setIsClosing(true);
1552
+ setAnimationClass("sh-dialog-animate-out");
1553
+ setBackdropAnimationClass("sh-backdrop-animate-out");
1554
+ if (closeTimeout) {
1555
+ clearTimeout(closeTimeout);
1556
+ }
1557
+ setCloseTimeout(
1558
+ setTimeout(() => {
1559
+ setShowChat(false);
1560
+ setIsClosing(false);
1561
+ setAnimationClass("");
1562
+ setBackdropAnimationClass("");
1563
+ setCloseTimeout(null);
1564
+ if (props.onClose) {
1565
+ props.onClose();
1566
+ }
1567
+ }, 200)
1568
+ );
1569
+ } else {
1570
+ if (closeTimeout) {
1571
+ clearTimeout(closeTimeout);
1572
+ setCloseTimeout(null);
1573
+ }
1574
+ setShowChat(true);
1575
+ setIsClosing(false);
1576
+ setAnimationClass("sh-dialog-animate");
1577
+ setBackdropAnimationClass("sh-backdrop-animate");
1578
+ setTimeout(() => {
1579
+ setAnimationClass("");
1580
+ setBackdropAnimationClass("");
1581
+ }, 250);
808
1582
  }
809
1583
  }
810
1584
  function handleNewChat() {
811
1585
  setChatMessages([]);
812
1586
  service == null ? void 0 : service.resetSession();
813
1587
  }
814
- function onPopularItemsClick() {
815
- setInput(TRANSLATIONS.showPopularItems);
816
- handleSend();
817
- }
818
- function onCompareProductsClick() {
819
- setInput(TRANSLATIONS.compareProducts);
820
- handleSend();
821
- }
822
1588
  function onInputChange(event) {
823
1589
  setInput(event.target.value);
824
1590
  }
@@ -827,49 +1593,196 @@ function ShopPrompter(props) {
827
1593
  handleSend();
828
1594
  }
829
1595
  }
830
- function onHeaderButtonMouseEnter() {
831
- setIsHeaderButtonHovered(true);
1596
+ function handleTriggerClick(e) {
1597
+ if (props.chatPosition !== "dialog") return;
1598
+ if (!props.dialogTrigger) return;
1599
+ const isTargetClicked = typeof props.dialogTrigger === "string" ? e.target.closest(props.dialogTrigger) : (() => {
1600
+ let target = null;
1601
+ if (typeof props.dialogTrigger === "object") {
1602
+ if ("current" in props.dialogTrigger) {
1603
+ target = props.dialogTrigger.current;
1604
+ } else {
1605
+ target = props.dialogTrigger;
1606
+ }
1607
+ }
1608
+ return target && target.contains && target.contains(e.target);
1609
+ })();
1610
+ if (isTargetClicked) {
1611
+ if (closeTimeout) {
1612
+ clearTimeout(closeTimeout);
1613
+ setCloseTimeout(null);
1614
+ }
1615
+ setShowChat(true);
1616
+ setIsClosing(false);
1617
+ setAnimationClass("sh-dialog-animate");
1618
+ setBackdropAnimationClass("sh-backdrop-animate");
1619
+ setTimeout(() => {
1620
+ setAnimationClass("");
1621
+ setBackdropAnimationClass("");
1622
+ }, 250);
1623
+ }
832
1624
  }
833
- function onHeaderButtonMouseLeave() {
834
- setIsHeaderButtonHovered(false);
1625
+ function loadCustomFont(fontFamily) {
1626
+ if (!fontFamily || typeof window === "undefined") return;
1627
+ const systemFonts = [
1628
+ "sans-serif",
1629
+ "serif",
1630
+ "monospace",
1631
+ "cursive",
1632
+ "fantasy",
1633
+ "system-ui",
1634
+ "-apple-system",
1635
+ "blinkmacsystemfont",
1636
+ "segoe ui",
1637
+ "roboto",
1638
+ "helvetica",
1639
+ "arial",
1640
+ "inherit"
1641
+ ];
1642
+ const cleanFont = fontFamily.split(",")[0].trim().replace(new RegExp(`['"]`, "g"), "");
1643
+ if (!cleanFont || systemFonts.includes(cleanFont.toLowerCase())) return;
1644
+ const linkId = `shopprompter-font-${cleanFont.toLowerCase().replace(new RegExp("\\s+", "g"), "-")}`;
1645
+ if (document.getElementById(linkId)) return;
1646
+ const link = document.createElement("link");
1647
+ link.id = linkId;
1648
+ link.rel = "stylesheet";
1649
+ const fontNameUrl = cleanFont.replace(new RegExp("\\s+", "g"), "+");
1650
+ link.href = `https://fonts.googleapis.com/css2?family=${fontNameUrl}:wght@400;500;600;700&display=swap`;
1651
+ document.head.appendChild(link);
835
1652
  }
836
- function doSomethingAsync() {
1653
+ function loadAgentExperience() {
837
1654
  void (async function() {
838
- console.log("## ~ ShopPrompter ~ state.service:", service);
839
1655
  if (!service) {
840
- console.warn("Service not initialized yet");
1656
+ console.warn(
1657
+ "Service not initialized yet! Cannot load AgentExperience."
1658
+ );
841
1659
  return;
842
1660
  }
843
1661
  const response = await (service == null ? void 0 : service.getAgentExperience());
844
- console.log("## ~ ShopPrompter ~ response:", response);
845
1662
  setAgentExperience(response);
846
1663
  })();
847
1664
  }
848
- useEffect(() => {
849
- const shopPrompterService = new ShopPrompterService();
850
- setService(shopPrompterService);
1665
+ function handleFeedback(messageId, messageContent, newFeedback) {
1666
+ const msg = chatMessages.find((m) => m.id === messageId);
1667
+ if (!msg) return;
1668
+ const currentFeedback = msg.feedback;
1669
+ const targetFeedback = currentFeedback === newFeedback ? "clear" : newFeedback;
1670
+ const oldMessages = [...chatMessages];
1671
+ setChatMessages(
1672
+ chatMessages.map((m) => {
1673
+ if (m.id === messageId) {
1674
+ return {
1675
+ ...m,
1676
+ feedback: targetFeedback === "clear" ? null : targetFeedback
1677
+ };
1678
+ }
1679
+ return m;
1680
+ })
1681
+ );
1682
+ setError(null);
1683
+ service == null ? void 0 : service.sendFeedback(messageId, messageContent, targetFeedback).catch((err) => {
1684
+ setChatMessages(oldMessages);
1685
+ setError((err == null ? void 0 : err.message) || TRANSLATIONS.feedbackError);
1686
+ });
1687
+ }
1688
+ function canShowFeedback(message) {
1689
+ if (message.role !== "assistant") return false;
1690
+ if (!message.content) return false;
1691
+ const lastMsg = chatMessages[chatMessages.length - 1];
1692
+ if (lastMsg && lastMsg.id === message.id && isLoading) {
1693
+ return false;
1694
+ }
1695
+ return true;
1696
+ }
1697
+ useEffect2(() => {
1698
+ if (typeof window !== "undefined" && !document.getElementById("lottie-player-script")) {
1699
+ const script = document.createElement("script");
1700
+ script.id = "lottie-player-script";
1701
+ script.src = "https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player";
1702
+ document.head.appendChild(script);
1703
+ }
1704
+ if (themeObj().fontFamily) {
1705
+ loadCustomFont(themeObj().fontFamily);
1706
+ }
1707
+ if (apiConfigObj()) {
1708
+ if (!isConfigInsufficient()) {
1709
+ const apiConfig = {
1710
+ ...apiConfigObj(),
1711
+ shopPrompterToken: props.shopPrompterToken || apiConfigObj().shopPrompterToken
1712
+ };
1713
+ const service2 = new ShopPrompterService(apiConfig);
1714
+ setService(service2);
1715
+ const savedMessages = service2.loadMessages();
1716
+ if (savedMessages.length > 0) {
1717
+ setChatMessages(savedMessages);
1718
+ }
1719
+ }
1720
+ } else {
1721
+ console.error("ShopPrompter: apiConfig prop is required!");
1722
+ }
1723
+ if ((props == null ? void 0 : props.chatPosition) === "right-panel" || (props == null ? void 0 : props.chatPosition) === "full-page") {
1724
+ setShowChat(true);
1725
+ }
1726
+ if (typeof window !== "undefined") {
1727
+ document.addEventListener("click", handleTriggerClick);
1728
+ }
851
1729
  }, []);
852
- useEffect(() => {
1730
+ useEffect2(() => {
853
1731
  if (service && !agentExperience) {
854
- doSomethingAsync();
855
- }
856
- if (agentExperience) {
857
- console.log("## ~ ShopPrompter ~ agentExperience updated:", {
858
- greeting: agentExperience.greeting,
859
- agentLogoUrl: agentExperience.agentLogoUrl
860
- });
1732
+ loadAgentExperience();
861
1733
  }
862
1734
  }, [service, agentExperience]);
863
- return /* @__PURE__ */ jsxs("div", { className: "shopprompter-sdk", children: [
864
- props.chatPosition === "classic-chatbot" ? /* @__PURE__ */ jsx(Fragment, { children: !showChat ? /* @__PURE__ */ jsx(
1735
+ useEffect2(() => {
1736
+ if (themeObj().fontFamily) {
1737
+ loadCustomFont(themeObj().fontFamily);
1738
+ }
1739
+ }, [themeObj().fontFamily || ""]);
1740
+ useEffect2(() => {
1741
+ if ((props == null ? void 0 : props.chatPosition) === "right-panel" || (props == null ? void 0 : props.chatPosition) === "full-page") {
1742
+ setShowChat(true);
1743
+ } else if ((props == null ? void 0 : props.chatPosition) === "dialog" || (props == null ? void 0 : props.chatPosition) === "classic-chatbot") {
1744
+ setShowChat(false);
1745
+ setIsClosing(false);
1746
+ setAnimationClass("");
1747
+ setBackdropAnimationClass("");
1748
+ }
1749
+ }, [(props == null ? void 0 : props.chatPosition) || ""]);
1750
+ return /* @__PURE__ */ jsxs4("div", { className: "shopprompter-sdk", children: [
1751
+ /* @__PURE__ */ jsx4("style", { dangerouslySetInnerHTML: { __html: ANIMATION_STYLES } }),
1752
+ /* @__PURE__ */ jsx4(
1753
+ "div",
1754
+ {
1755
+ onClick: (e) => toggleChat(),
1756
+ style: {
1757
+ ...styles2.backdrop,
1758
+ display: props.chatPosition === "dialog" && (showChat || isClosing) ? "block" : "none"
1759
+ },
1760
+ className: backdropAnimationClass
1761
+ }
1762
+ ),
1763
+ props.chatPosition === "classic-chatbot" ? /* @__PURE__ */ jsx4(Fragment2, { children: !showChat ? /* @__PURE__ */ jsx4(
865
1764
  "button",
866
1765
  {
867
- 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",
868
1766
  onClick: (e) => toggleChat(),
869
1767
  style: {
870
- boxShadow: "0 0 0 8px rgba(37, 99, 235, 0.2)"
1768
+ position: "fixed",
1769
+ bottom: "1.5rem",
1770
+ right: "1.5rem",
1771
+ width: "4rem",
1772
+ height: "4rem",
1773
+ backgroundColor: themeObj().actionColor || "#2563eb",
1774
+ borderRadius: "9999px",
1775
+ zIndex: 50,
1776
+ display: "flex",
1777
+ alignItems: "center",
1778
+ justifyContent: "center",
1779
+ transition: "background-color 0.2s",
1780
+ border: "none",
1781
+ cursor: "pointer",
1782
+ boxShadow: themeObj().actionColor ? `0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05), 0 0 0 8px ${themeObj().actionColor}33` : "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)",
1783
+ fontFamily: themeObj().fontFamily || void 0
871
1784
  },
872
- children: /* @__PURE__ */ jsx(
1785
+ children: /* @__PURE__ */ jsx4(
873
1786
  "img",
874
1787
  {
875
1788
  alt: "Chat",
@@ -882,259 +1795,406 @@ function ShopPrompter(props) {
882
1795
  )
883
1796
  }
884
1797
  ) : null }) : null,
885
- showChat ? /* @__PURE__ */ jsxs("div", { style: containerStyle(), className: containerClass(), children: [
886
- /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
887
- /* @__PURE__ */ jsxs("div", { style: styles.subHeaderContainer, children: [
888
- /* @__PURE__ */ jsxs(
889
- "svg",
890
- {
891
- xmlns: "http://www.w3.org/2000/svg",
892
- viewBox: "0 0 46 47",
893
- width: "24",
894
- height: "24",
895
- fill: "none",
896
- children: [
897
- /* @__PURE__ */ jsx(
898
- "path",
899
- {
900
- fill: "url(#a)",
901
- d: "M16.452 32.747c-1.587 0-2.874-1.3-2.874-2.903V14.25h5.259V0H5.747C2.576 0 0 2.6 0 5.806v21.139c0 3.208 2.575 5.805 5.748 5.805h10.704v-.003Z"
902
- }
903
- ),
904
- /* @__PURE__ */ jsx(
905
- "path",
906
- {
907
- fill: "url(#b)",
908
- d: "M19.326 0c-3.173 0-5.748 2.6-5.748 5.806v8.444h15.438c1.586 0 2.874 1.3 2.874 2.902v3.924H46V0H19.326Z"
909
- }
910
- ),
911
- /* @__PURE__ */ jsx(
912
- "path",
913
- {
914
- fill: "url(#c)",
915
- d: "M40.252 14.25H29.016c1.586 0 2.874 1.3 2.874 2.902v15.595h-6.751V47h15.117c3.173 0 5.748-2.6 5.748-5.806V20.055c0-3.205-2.575-5.806-5.748-5.806h-.004Z"
1798
+ showChat || isClosing ? /* @__PURE__ */ jsxs4("div", { style: containerStyle(), className: containerClass(), children: [
1799
+ /* @__PURE__ */ jsxs4(
1800
+ "div",
1801
+ {
1802
+ style: {
1803
+ ...styles2.header,
1804
+ backgroundColor: themeObj().headerBackgroundColor || "transparent"
1805
+ },
1806
+ children: [
1807
+ themeObj().showAgentName !== false ? /* @__PURE__ */ jsxs4("div", { style: styles2.subHeaderContainer, children: [
1808
+ (agentExperience == null ? void 0 : agentExperience.agentLogoUrl) ? /* @__PURE__ */ jsx4(
1809
+ "img",
1810
+ {
1811
+ src: agentExperience.agentLogoUrl,
1812
+ alt: agentExperience.agentName,
1813
+ style: {
1814
+ width: "24px",
1815
+ height: "24px",
1816
+ borderRadius: "4px",
1817
+ objectFit: "cover"
916
1818
  }
917
- ),
918
- /* @__PURE__ */ jsx(
919
- "path",
920
- {
921
- fill: "url(#d)",
922
- d: "M8.669 32.75H5.751c-3.173 0-5.747-2.6-5.747-5.805V47h26.142c3.172 0 5.747-2.6 5.747-5.806V32.75H8.67Z"
923
- }
924
- ),
925
- /* @__PURE__ */ jsxs("defs", { children: [
926
- /* @__PURE__ */ jsxs(
927
- "linearGradient",
928
- {
929
- id: "a",
930
- x1: "14.3",
931
- x2: "3.322",
932
- y1: "22.494",
933
- y2: "4.382",
934
- gradientUnits: "userSpaceOnUse",
935
- children: [
936
- /* @__PURE__ */ jsx("stop", { stopColor: "#B0145C" }),
937
- /* @__PURE__ */ jsx("stop", { offset: ".37", stopColor: "#AE2E9A" }),
938
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#AD59FF" })
939
- ]
940
- }
941
- ),
942
- /* @__PURE__ */ jsxs(
943
- "linearGradient",
944
- {
945
- id: "b",
946
- x1: "21.156",
947
- x2: "40.431",
948
- y1: "21.216",
949
- y2: "1.624",
950
- gradientUnits: "userSpaceOnUse",
951
- children: [
952
- /* @__PURE__ */ jsx("stop", { offset: ".08", stopColor: "#E7A2FF" }),
953
- /* @__PURE__ */ jsx("stop", { offset: ".37", stopColor: "#E983CD" }),
954
- /* @__PURE__ */ jsx("stop", { offset: ".99", stopColor: "#F03A58" })
955
- ]
956
- }
957
- ),
958
- /* @__PURE__ */ jsxs(
959
- "linearGradient",
960
- {
961
- id: "c",
962
- x1: "30.464",
963
- x2: "46.567",
964
- y1: "27.405",
965
- y2: "42.472",
966
- gradientUnits: "userSpaceOnUse",
967
- children: [
968
- /* @__PURE__ */ jsx("stop", { stopColor: "#B0145C" }),
969
- /* @__PURE__ */ jsx("stop", { offset: ".02", stopColor: "#B11861" }),
970
- /* @__PURE__ */ jsx("stop", { offset: ".27", stopColor: "#C44999" }),
971
- /* @__PURE__ */ jsx("stop", { offset: ".5", stopColor: "#D36FC5" }),
972
- /* @__PURE__ */ jsx("stop", { offset: ".71", stopColor: "#DE8BE4" }),
973
- /* @__PURE__ */ jsx("stop", { offset: ".88", stopColor: "#E49BF8" }),
974
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#E7A2FF" })
975
- ]
976
- }
977
- ),
978
- /* @__PURE__ */ jsxs(
979
- "linearGradient",
1819
+ }
1820
+ ) : null,
1821
+ (agentExperience == null ? void 0 : agentExperience.agentName) ? /* @__PURE__ */ jsx4("span", { style: styles2.headerText, children: agentExperience.agentName }) : null
1822
+ ] }) : /* @__PURE__ */ jsx4(Fragment2, { children: /* @__PURE__ */ jsx4("div", { style: styles2.subHeaderContainer }) }),
1823
+ !hasToken() && ((_a = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a.apiKey) ? /* @__PURE__ */ jsx4("div", { style: styles2.warningBanner, children: "API Key is only for development purposes" }) : null,
1824
+ /* @__PURE__ */ jsxs4("div", { style: styles2.subHeaderContainer, children: [
1825
+ /* @__PURE__ */ jsx4(
1826
+ "button",
1827
+ {
1828
+ className: "sh-header-btn",
1829
+ onClick: (e) => handleNewChat(),
1830
+ style: styles2.headerButton,
1831
+ children: TRANSLATIONS.newChat
1832
+ }
1833
+ ),
1834
+ props.chatPosition === "classic-chatbot" || props.chatPosition === "right-panel" || props.chatPosition === "dialog" ? /* @__PURE__ */ jsx4(
1835
+ "button",
1836
+ {
1837
+ onClick: (e) => toggleChat(),
1838
+ style: styles2.ButtonSheetButton,
1839
+ children: "\xD7"
1840
+ }
1841
+ ) : null
1842
+ ] })
1843
+ ]
1844
+ }
1845
+ ),
1846
+ isConfigInsufficient() ? /* @__PURE__ */ jsxs4("div", { style: styles2.insufficientConfigContainer, children: [
1847
+ /* @__PURE__ */ jsx4("div", { style: styles2.insufficientConfigIconContainer, children: /* @__PURE__ */ jsxs4(
1848
+ "svg",
1849
+ {
1850
+ width: "48",
1851
+ height: "48",
1852
+ viewBox: "0 0 24 24",
1853
+ fill: "none",
1854
+ stroke: "currentColor",
1855
+ strokeWidth: "2",
1856
+ strokeLinecap: "round",
1857
+ strokeLinejoin: "round",
1858
+ style: {
1859
+ color: "#ef4444"
1860
+ },
1861
+ children: [
1862
+ /* @__PURE__ */ jsx4("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
1863
+ /* @__PURE__ */ jsx4("path", { d: "M7 11V7a5 5 0 0 1 9.9-1" })
1864
+ ]
1865
+ }
1866
+ ) }),
1867
+ /* @__PURE__ */ jsx4(
1868
+ "h3",
1869
+ {
1870
+ style: {
1871
+ ...styles2.insufficientConfigTitle,
1872
+ fontFamily: themeObj().fontFamily || void 0
1873
+ },
1874
+ children: "Configuration Error"
1875
+ }
1876
+ ),
1877
+ /* @__PURE__ */ jsx4(
1878
+ "p",
1879
+ {
1880
+ style: {
1881
+ ...styles2.insufficientConfigMessage,
1882
+ fontFamily: themeObj().fontFamily || void 0
1883
+ },
1884
+ children: "ShopPrompter requires a secure token or API key to initialize. Please check your setup."
1885
+ }
1886
+ ),
1887
+ /* @__PURE__ */ jsxs4(
1888
+ "div",
1889
+ {
1890
+ style: {
1891
+ ...styles2.insufficientConfigDetails,
1892
+ fontFamily: themeObj().fontFamily || void 0
1893
+ },
1894
+ children: [
1895
+ /* @__PURE__ */ jsx4(
1896
+ "div",
1897
+ {
1898
+ style: {
1899
+ fontWeight: 600,
1900
+ marginBottom: "0.25rem"
1901
+ },
1902
+ children: "Missing Parameters:"
1903
+ }
1904
+ ),
1905
+ /* @__PURE__ */ jsxs4(
1906
+ "div",
1907
+ {
1908
+ style: {
1909
+ display: "flex",
1910
+ flexDirection: "column",
1911
+ gap: "0.25rem",
1912
+ fontFamily: "monospace",
1913
+ fontSize: "0.75rem"
1914
+ },
1915
+ children: [
1916
+ /* @__PURE__ */ jsx4(
1917
+ "span",
1918
+ {
1919
+ style: {
1920
+ color: "#ef4444"
1921
+ },
1922
+ children: "\u2717 shopPrompterToken (not found)"
1923
+ }
1924
+ ),
1925
+ /* @__PURE__ */ jsx4(
1926
+ "span",
1927
+ {
1928
+ style: {
1929
+ color: "#ef4444"
1930
+ },
1931
+ children: "\u2717 apiConfig.apiKey (not found)"
1932
+ }
1933
+ )
1934
+ ]
1935
+ }
1936
+ )
1937
+ ]
1938
+ }
1939
+ )
1940
+ ] }) : null,
1941
+ !isConfigInsufficient() ? /* @__PURE__ */ jsxs4(
1942
+ "div",
1943
+ {
1944
+ style: {
1945
+ display: "flex",
1946
+ flexDirection: "column",
1947
+ flex: 1,
1948
+ overflow: "hidden"
1949
+ },
1950
+ children: [
1951
+ /* @__PURE__ */ jsxs4(
1952
+ "div",
1953
+ {
1954
+ id: "shop-prompter-chat-container",
1955
+ style: {
1956
+ ...styles2.chatContainer,
1957
+ backgroundColor: themeObj().mainBackgroundColor || styles2.chatContainer.backgroundColor
1958
+ },
1959
+ children: [
1960
+ showWelcome() ? /* @__PURE__ */ jsxs4("div", { style: styles2.welcomeContainer, children: [
1961
+ /* @__PURE__ */ jsx4(
1962
+ "img",
1963
+ {
1964
+ alt: "ShopPrompter",
1965
+ src: (agentExperience == null ? void 0 : agentExperience.agentLogoUrl) ? agentExperience.agentLogoUrl : ICONS.shopprompter,
1966
+ style: {
1967
+ width: "64px",
1968
+ height: "64px",
1969
+ marginBottom: "24px",
1970
+ borderRadius: "12px",
1971
+ objectFit: "cover"
1972
+ }
1973
+ }
1974
+ ),
1975
+ /* @__PURE__ */ jsx4(
1976
+ "h3",
1977
+ {
1978
+ style: {
1979
+ ...styles2.welcomeTitle,
1980
+ fontFamily: themeObj().fontFamily || styles2.welcomeTitle.fontFamily
1981
+ },
1982
+ children: ((_b = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _b.title) || TRANSLATIONS.welcomeToShopPrompter
1983
+ }
1984
+ ),
1985
+ /* @__PURE__ */ jsx4(
1986
+ "p",
1987
+ {
1988
+ style: {
1989
+ ...styles2.welcomeDescription,
1990
+ fontFamily: themeObj().fontFamily || styles2.welcomeDescription.fontFamily
1991
+ },
1992
+ children: ((_c = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _c.description) || TRANSLATIONS.welcomeDescription
1993
+ }
1994
+ ),
1995
+ /* @__PURE__ */ jsx4("div", { style: styles2.buttonContainer, children: (_d = prompts()) == null ? void 0 : _d.map((item) => /* @__PURE__ */ jsx4(
1996
+ "button",
1997
+ {
1998
+ style: styles2.button,
1999
+ onClick: (event) => {
2000
+ setInput(item.prompt);
2001
+ handleSend(item.prompt);
2002
+ },
2003
+ children: item.prompt
2004
+ },
2005
+ item.prompt
2006
+ )) })
2007
+ ] }) : null,
2008
+ !showWelcome() ? /* @__PURE__ */ jsx4(
2009
+ "div",
980
2010
  {
981
- id: "d",
982
- x1: "23.356",
983
- x2: "-.618",
984
- y1: "44.082",
985
- y2: "30.739",
986
- gradientUnits: "userSpaceOnUse",
987
- children: [
988
- /* @__PURE__ */ jsx("stop", { stopColor: "#AD59FF" }),
989
- /* @__PURE__ */ jsx("stop", { offset: ".1", stopColor: "#B455EB" }),
990
- /* @__PURE__ */ jsx("stop", { offset: ".54", stopColor: "#D4469C" }),
991
- /* @__PURE__ */ jsx("stop", { offset: ".85", stopColor: "#E83D6B" }),
992
- /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#F03A58" })
993
- ]
2011
+ style: {
2012
+ width: "100%"
2013
+ },
2014
+ children: chatMessages == null ? void 0 : chatMessages.map((message) => /* @__PURE__ */ jsxs4("div", { children: [
2015
+ message.role === "user" ? /* @__PURE__ */ jsx4("div", { style: styles2.messageContainerUser, children: /* @__PURE__ */ jsx4(
2016
+ "div",
2017
+ {
2018
+ style: {
2019
+ ...styles2.messageBubbleUser,
2020
+ backgroundColor: themeObj().userMessageBackgroundColor || styles2.messageBubbleUser.backgroundColor
2021
+ },
2022
+ children: message.content
2023
+ }
2024
+ ) }) : null,
2025
+ message.role === "assistant" ? /* @__PURE__ */ jsxs4("div", { style: styles2.messageContainerAssistant, children: [
2026
+ /* @__PURE__ */ jsxs4(
2027
+ "div",
2028
+ {
2029
+ style: {
2030
+ ...styles2.messageBubbleAssistant,
2031
+ backgroundColor: themeObj().assistantMessageBackgroundColor || styles2.messageBubbleAssistant.backgroundColor
2032
+ },
2033
+ children: [
2034
+ /* @__PURE__ */ jsx4(
2035
+ "div",
2036
+ {
2037
+ dangerouslySetInnerHTML: {
2038
+ __html: parseMarkdown(message.content)
2039
+ }
2040
+ }
2041
+ ),
2042
+ !message.content && isLoading ? /* @__PURE__ */ jsx4(Fragment2, { children: (agentExperience == null ? void 0 : agentExperience.loadingIndicatorUrl) ? /* @__PURE__ */ jsx4(
2043
+ "lottie-player",
2044
+ {
2045
+ background: "transparent",
2046
+ speed: "1",
2047
+ src: agentExperience.loadingIndicatorUrl,
2048
+ style: {
2049
+ width: "40px",
2050
+ height: "40px"
2051
+ },
2052
+ loop: true,
2053
+ autoplay: true
2054
+ }
2055
+ ) : /* @__PURE__ */ jsx4("div", { style: styles2.thinkingIndicator, children: /* @__PURE__ */ jsxs4(
2056
+ "svg",
2057
+ {
2058
+ width: "24",
2059
+ height: "24",
2060
+ viewBox: "0 0 24 24",
2061
+ fill: "none",
2062
+ stroke: "currentColor",
2063
+ strokeWidth: "2",
2064
+ strokeLinecap: "round",
2065
+ strokeLinejoin: "round",
2066
+ style: {
2067
+ color: "#6b7280"
2068
+ },
2069
+ children: [
2070
+ /* @__PURE__ */ jsx4("path", { d: THINKING_SPINNER }),
2071
+ /* @__PURE__ */ jsx4(
2072
+ "animateTransform",
2073
+ {
2074
+ attributeName: "transform",
2075
+ type: "rotate",
2076
+ from: "0 12 12",
2077
+ to: "360 12 12",
2078
+ dur: "1s",
2079
+ repeatCount: "indefinite"
2080
+ }
2081
+ )
2082
+ ]
2083
+ }
2084
+ ) }) }) : null
2085
+ ]
2086
+ }
2087
+ ),
2088
+ canShowFeedback(message) ? /* @__PURE__ */ jsxs4("div", { style: styles2.feedbackRow, children: [
2089
+ /* @__PURE__ */ jsx4(
2090
+ "button",
2091
+ {
2092
+ className: "sh-feedback-btn",
2093
+ onClick: (event) => handleFeedback(
2094
+ message.id,
2095
+ message.content,
2096
+ "upvote"
2097
+ ),
2098
+ style: styles2.feedbackButton,
2099
+ children: /* @__PURE__ */ jsx4(
2100
+ thumbs_up_icon_component_default,
2101
+ {
2102
+ fill: message.feedback === "upvote" ? themeObj().actionColor || "#2563eb" : "none",
2103
+ stroke: message.feedback === "upvote" ? themeObj().actionColor || "#2563eb" : "currentColor"
2104
+ }
2105
+ )
2106
+ }
2107
+ ),
2108
+ /* @__PURE__ */ jsx4(
2109
+ "button",
2110
+ {
2111
+ className: "sh-feedback-btn",
2112
+ onClick: (event) => handleFeedback(
2113
+ message.id,
2114
+ message.content,
2115
+ "downvote"
2116
+ ),
2117
+ style: styles2.feedbackButton,
2118
+ children: /* @__PURE__ */ jsx4(
2119
+ thumbs_down_icon_component_default,
2120
+ {
2121
+ fill: message.feedback === "downvote" ? themeObj().actionColor || "#2563eb" : "none",
2122
+ stroke: message.feedback === "downvote" ? themeObj().actionColor || "#2563eb" : "currentColor"
2123
+ }
2124
+ )
2125
+ }
2126
+ )
2127
+ ] }) : null,
2128
+ getShowProducts(message) ? /* @__PURE__ */ jsx4(
2129
+ product_card_list_component_default,
2130
+ {
2131
+ skus: message.productSkus,
2132
+ defaultLocale: props.defaultLocale,
2133
+ showPriceIfEmpty: showPriceIfEmptyVal(),
2134
+ visibleFields: visibleFieldsList()
2135
+ }
2136
+ ) : null
2137
+ ] }) : null
2138
+ ] }, message.id))
994
2139
  }
995
- )
996
- ] })
997
- ]
998
- }
999
- ),
1000
- /* @__PURE__ */ jsx("span", { style: styles.headerText, children: "ShopPrompter\xAE" })
1001
- ] }),
1002
- /* @__PURE__ */ jsxs("div", { style: styles.subHeaderContainer, children: [
1003
- /* @__PURE__ */ jsx(
1004
- "button",
1005
- {
1006
- onClick: (e) => handleNewChat(),
1007
- onMouseEnter: (e) => onHeaderButtonMouseEnter(),
1008
- onMouseLeave: (e) => onHeaderButtonMouseLeave(),
1009
- style: {
1010
- ...styles.headerButton,
1011
- ...isHeaderButtonHovered ? styles.headerButton.onHover : {}
1012
- },
1013
- children: TRANSLATIONS.newChat
1014
- }
1015
- ),
1016
- props.chatPosition === "classic-chatbot" || props.chatPosition === "right-panel" || props.chatPosition === "bottom-sheet" ? /* @__PURE__ */ jsx(
1017
- "button",
1018
- {
1019
- onClick: (e) => toggleChat(),
1020
- style: styles.ButtonSheetButton,
1021
- children: "\xD7"
1022
- }
1023
- ) : null
1024
- ] })
1025
- ] }),
1026
- /* @__PURE__ */ jsxs("div", { style: styles.chatContainer, children: [
1027
- showWelcome() ? /* @__PURE__ */ jsxs("div", { style: styles.welcomeContainer, children: [
1028
- /* @__PURE__ */ jsx(
1029
- "img",
1030
- {
1031
- alt: "ShopPrompter",
1032
- src: (agentExperience == null ? void 0 : agentExperience.agentLogoUrl) ? agentExperience.agentLogoUrl : ICONS.shopprompter,
1033
- style: {
1034
- width: "64px",
1035
- height: "64px",
1036
- marginBottom: "24px"
1037
- }
1038
- }
1039
- ),
1040
- /* @__PURE__ */ jsx("h3", { style: styles.welcomeTitle, children: ((_a = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _a.title) || TRANSLATIONS.welcomeToShopPrompter }),
1041
- /* @__PURE__ */ jsx("p", { style: styles.welcomeDescription, children: ((_b = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _b.description) || TRANSLATIONS.welcomeDescription }),
1042
- /* @__PURE__ */ jsxs("div", { style: styles.buttonContainer, children: [
1043
- /* @__PURE__ */ jsx(
1044
- "button",
1045
- {
1046
- style: styles.button,
1047
- onClick: (e) => onPopularItemsClick(),
1048
- children: TRANSLATIONS.showPopularItems
2140
+ ) : null,
2141
+ error ? /* @__PURE__ */ jsxs4("div", { style: styles2.errorContainer, children: [
2142
+ "Error: ",
2143
+ error
2144
+ ] }) : null
2145
+ ]
1049
2146
  }
1050
2147
  ),
1051
- /* @__PURE__ */ jsx(
1052
- "button",
2148
+ /* @__PURE__ */ jsxs4(
2149
+ "div",
1053
2150
  {
1054
- style: styles.button,
1055
- onClick: (e) => onCompareProductsClick(),
1056
- children: TRANSLATIONS.compareProducts
1057
- }
1058
- )
1059
- ] })
1060
- ] }) : /* @__PURE__ */ jsx(Fragment, { children: (_c = messages()) == null ? void 0 : _c.map((message) => {
1061
- var _a2;
1062
- return /* @__PURE__ */ jsxs(
1063
- "div",
1064
- {
1065
- style: message.role === "user" ? styles.messageContainerUser : styles.messageContainerAssistant,
1066
- children: [
1067
- /* @__PURE__ */ jsxs(
1068
- "div",
1069
- {
1070
- style: message.role === "user" ? styles.messageBubbleUser : styles.messageBubbleAssistant,
1071
- children: [
1072
- message.content,
1073
- !message.content ? /* @__PURE__ */ jsx(Fragment, { children: message.role === "assistant" ? /* @__PURE__ */ jsx(Fragment, { children: isLoading ? /* @__PURE__ */ jsx("div", { style: styles.thinkingIndicator, children: TRANSLATIONS.thinking }) : null }) : null }) : null
1074
- ]
1075
- }
1076
- ),
1077
- message.role === "assistant" ? /* @__PURE__ */ jsx("div", { style: styles.productCardsContainer, children: (_a2 = message.safeProductSkus) == null ? void 0 : _a2.map((sku) => /* @__PURE__ */ jsxs("div", { style: styles.productCard, children: [
1078
- /* @__PURE__ */ jsx("div", { style: styles.productImageContainer, children: /* @__PURE__ */ jsx(
1079
- "img",
1080
- {
1081
- src: getProductImageUrl(sku),
1082
- alt: sku,
1083
- style: {
1084
- maxHeight: "100%",
1085
- maxWidth: "100%"
2151
+ style: {
2152
+ ...styles2.inputSection,
2153
+ backgroundColor: themeObj().mainBackgroundColor || styles2.inputSection.backgroundColor
2154
+ },
2155
+ children: [
2156
+ /* @__PURE__ */ jsxs4("div", { style: styles2.inputWrapper, children: [
2157
+ /* @__PURE__ */ jsx4(
2158
+ "input",
2159
+ {
2160
+ id: "shop-prompter-input",
2161
+ type: "text",
2162
+ style: styles2.input,
2163
+ placeholder: (agentExperience == null ? void 0 : agentExperience.hintText) || TRANSLATIONS.askMeAnything,
2164
+ value: input,
2165
+ onInput: (e) => onInputChange(e),
2166
+ onKeyDown: (e) => onInputKeyDown(e)
1086
2167
  }
1087
- }
1088
- ) }),
1089
- /* @__PURE__ */ jsxs("div", { style: styles.productInfo, children: [
1090
- /* @__PURE__ */ jsx("p", { style: styles.productSku, children: sku }),
1091
- /* @__PURE__ */ jsx(
1092
- "a",
2168
+ ),
2169
+ /* @__PURE__ */ jsx4(
2170
+ "button",
1093
2171
  {
1094
- href: getProductLink(sku),
1095
- style: styles.productLink,
1096
- children: "VIEW DETAILS"
2172
+ onClick: (e) => handleSend(),
2173
+ style: {
2174
+ ...styles2.formButton,
2175
+ ...styles2.sendButton,
2176
+ backgroundColor: themeObj().actionColor || styles2.sendButton.backgroundColor
2177
+ },
2178
+ children: /* @__PURE__ */ jsx4(
2179
+ "img",
2180
+ {
2181
+ alt: "Send",
2182
+ src: ICONS.sendHorizontal,
2183
+ style: {
2184
+ padding: "4px"
2185
+ }
2186
+ }
2187
+ )
1097
2188
  }
1098
2189
  )
1099
- ] })
1100
- ] }, sku)) }) : null
1101
- ]
1102
- },
1103
- message.id
1104
- );
1105
- }) }),
1106
- error ? /* @__PURE__ */ jsxs("div", { style: styles.errorContainer, children: [
1107
- "Error: ",
1108
- error
1109
- ] }) : null
1110
- ] }),
1111
- /* @__PURE__ */ jsxs("div", { style: styles.inputSection, children: [
1112
- /* @__PURE__ */ jsxs("div", { style: styles.inputWrapper, children: [
1113
- /* @__PURE__ */ jsx(
1114
- "input",
1115
- {
1116
- type: "text",
1117
- style: styles.input,
1118
- placeholder: TRANSLATIONS.askMeAnything,
1119
- value: input,
1120
- onInput: (e) => onInputChange(e),
1121
- onKeyDown: (e) => onInputKeyDown(e)
1122
- }
1123
- ),
1124
- /* @__PURE__ */ jsx(
1125
- "button",
1126
- {
1127
- onClick: (e) => handleSend(),
1128
- style: {
1129
- ...styles.formButton,
1130
- ...styles.sendButton
1131
- },
1132
- children: /* @__PURE__ */ jsx("img", { alt: "Send", src: ICONS.sendHorizontal })
1133
- }
1134
- )
1135
- ] }),
1136
- /* @__PURE__ */ jsx("p", { style: styles.disclaimer, children: "AI content may be inaccurate." })
1137
- ] })
2190
+ ] }),
2191
+ /* @__PURE__ */ jsx4("p", { style: styles2.disclaimer, children: "AI content may be inaccurate." })
2192
+ ]
2193
+ }
2194
+ )
2195
+ ]
2196
+ }
2197
+ ) : null
1138
2198
  ] }) : null
1139
2199
  ] });
1140
2200
  }