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