@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.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,297 @@ 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
+ productDynamicField: {
804
+ fontSize: "0.6875rem",
805
+ color: "#6b7280",
806
+ margin: 0,
807
+ whiteSpace: "nowrap",
808
+ overflow: "hidden",
809
+ textOverflow: "ellipsis"
810
+ },
811
+ productPrice: {
812
+ fontSize: "0.8125rem",
813
+ fontWeight: 500,
814
+ color: "#4b5563",
815
+ margin: 0
816
+ },
817
+ statusContainer: {
818
+ padding: "0.5rem 0",
819
+ fontSize: "0.75rem",
820
+ color: "#6b7280",
821
+ display: "flex",
822
+ alignItems: "center",
823
+ gap: "0.5rem"
824
+ },
825
+ errorText: {
826
+ color: "#ef4444"
827
+ },
828
+ spinner: {
829
+ color: "#6b7280"
830
+ },
831
+ wrapper: {
832
+ width: "100%",
833
+ maxWidth: "100%",
834
+ boxSizing: "border-box",
835
+ overflow: "hidden"
836
+ }
837
+ };
838
+ function ProductCardList(props) {
839
+ const [products, setProducts] = (0, import_react.useState)(() => []);
840
+ const [loading, setLoading] = (0, import_react.useState)(() => false);
841
+ const [error, setError] = (0, import_react.useState)(() => null);
842
+ function fetchProducts() {
843
+ let skusList = props.skus;
844
+ if (typeof skusList === "string") {
845
+ skusList = skusList.split(",").map((s) => s.trim()).filter(Boolean);
846
+ }
847
+ if (!skusList || skusList.length === 0) {
848
+ setProducts([]);
849
+ setLoading(false);
850
+ return;
851
+ }
852
+ if (productApi.isCached(skusList)) {
853
+ setProducts(productApi.getCached(skusList));
854
+ setLoading(false);
855
+ setError(null);
856
+ return;
857
+ }
858
+ setLoading(true);
859
+ setError(null);
860
+ productApi.getProducts(skusList).then((data) => {
861
+ setProducts(data || []);
862
+ setLoading(false);
863
+ }).catch((err) => {
864
+ console.error("Failed to fetch products:", err);
865
+ setError((err == null ? void 0 : err.message) || "Failed to load products");
866
+ setLoading(false);
867
+ });
868
+ }
869
+ function getProductName(product) {
870
+ var _a;
871
+ const locale = props.defaultLocale || "de";
872
+ const localized = ((_a = product.localization) == null ? void 0 : _a[locale]) || Object.values(product.localization || {})[0];
873
+ return (localized == null ? void 0 : localized.name) || product.sku;
874
+ }
875
+ function showPriceIfEmptyVal() {
876
+ const val = props.showPriceIfEmpty;
877
+ if (typeof val === "string") {
878
+ return val === "true";
879
+ }
880
+ return val != null ? val : false;
881
+ }
882
+ function visibleFieldsList() {
883
+ const val = props.visibleFields;
884
+ if (typeof val === "string") {
885
+ try {
886
+ return JSON.parse(val);
887
+ } catch (e) {
888
+ return val.split(",").map((s) => s.trim()).filter(Boolean);
889
+ }
890
+ }
891
+ return val || [];
892
+ }
893
+ function getDynamicField(product, field) {
894
+ var _a;
895
+ const locale = props.defaultLocale || "de";
896
+ const localized = ((_a = product.localization) == null ? void 0 : _a[locale]) || Object.values(product.localization || {})[0];
897
+ if (!localized) return void 0;
898
+ const parts = field.split(".");
899
+ let current = localized;
900
+ for (let i = 0; i < parts.length; i++) {
901
+ if (current === void 0 || current === null) return void 0;
902
+ current = current[parts[i]];
903
+ }
904
+ return current;
905
+ }
906
+ function getProductPrice(product) {
907
+ if (!product.pricing) return "";
908
+ const priceVal = product.pricing.gross;
909
+ const currency = product.pricing.currency;
910
+ if (priceVal === void 0 || priceVal === null) return "";
911
+ if (priceVal === 0 && !showPriceIfEmptyVal()) return "";
912
+ return priceVal.toFixed(2) + " " + (currency || "\u20AC");
913
+ }
914
+ function getProductImage(product) {
915
+ var _a;
916
+ return ((_a = product.images) == null ? void 0 : _a[0]) || "https://placehold.co/150x150?text=" + product.sku;
917
+ }
918
+ (0, import_react.useEffect)(() => {
919
+ fetchProducts();
920
+ }, []);
921
+ (0, import_react.useEffect)(() => {
922
+ fetchProducts();
923
+ }, [
924
+ props.skus ? Array.isArray(props.skus) ? props.skus.join(",") : props.skus : ""
925
+ ]);
926
+ 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: [
927
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: styles.statusContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Loading products..." }) }) : null,
928
+ !loading && error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: styles.statusContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: styles.errorText, children: [
929
+ "Error: ",
930
+ error
931
+ ] }) }) : null,
932
+ !loading && products && products.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: styles.productCardsContainer, children: products == null ? void 0 : products.map((product) => {
933
+ var _a;
934
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: styles.productCard, children: [
935
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: styles.productImageContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
936
+ "img",
937
+ {
938
+ src: getProductImage(product),
939
+ alt: getProductName(product),
940
+ style: styles.productImage
941
+ }
942
+ ) }),
943
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: styles.productInfo, children: [
944
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
945
+ "p",
946
+ {
947
+ style: styles.productName,
948
+ title: getProductName(product),
949
+ children: getProductName(product)
950
+ }
951
+ ),
952
+ (_a = visibleFieldsList()) == null ? void 0 : _a.map(
953
+ (field) => getDynamicField(product, field) !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
954
+ "p",
955
+ {
956
+ style: styles.productDynamicField,
957
+ title: String(getDynamicField(product, field)),
958
+ children: String(getDynamicField(product, field))
959
+ }
960
+ ) : null
961
+ ),
962
+ getProductPrice(product) !== "" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: styles.productPrice, children: getProductPrice(product) }) : null
963
+ ] })
964
+ ] }, product.sku);
965
+ }) }) : null
966
+ ] }) }) : null });
967
+ }
968
+ var product_card_list_component_default = ProductCardList;
969
+
970
+ // src/shop-prompter.component.jsx
971
+ var import_jsx_runtime4 = require("react/jsx-runtime");
972
+ var THINKING_SPINNER = "M21 12a9 9 0 1 1-6.219-8.56";
973
+ var styles2 = {
478
974
  header: {
479
975
  display: "flex",
480
976
  alignItems: "center",
481
977
  justifyContent: "space-between",
482
- padding: "16px"
978
+ padding: "16px",
979
+ borderBottom: "1px solid #e5e7eb"
483
980
  },
484
981
  subHeaderContainer: {
485
982
  display: "flex",
@@ -495,6 +992,7 @@ var styles = {
495
992
  border: "none",
496
993
  cursor: "pointer",
497
994
  transition: "background-color 0.2s, color 0.2s",
995
+ fontFamily: "inherit",
498
996
  onHover: {
499
997
  backgroundColor: "hsl(220 14% 96%)",
500
998
  color: "hsl(220 13% 13%)"
@@ -515,7 +1013,8 @@ var styles = {
515
1013
  gap: "0.5rem",
516
1014
  cursor: "pointer",
517
1015
  fontSize: "0.875rem",
518
- color: "#09090b"
1016
+ color: "#09090b",
1017
+ fontFamily: "inherit"
519
1018
  },
520
1019
  ButtonSheetButton: {
521
1020
  color: "#6b7280",
@@ -524,11 +1023,13 @@ var styles = {
524
1023
  cursor: "pointer",
525
1024
  padding: "0.25rem",
526
1025
  fontSize: "1.25rem",
527
- transition: "color 0.2s"
1026
+ transition: "color 0.2s",
1027
+ fontFamily: "inherit"
528
1028
  },
529
1029
  chatContainer: {
530
1030
  flex: 1,
531
1031
  overflowY: "auto",
1032
+ overflowX: "hidden",
532
1033
  padding: "1rem",
533
1034
  backgroundColor: "white"
534
1035
  },
@@ -574,12 +1075,17 @@ var styles = {
574
1075
  messageContainerUser: {
575
1076
  display: "flex",
576
1077
  flexDirection: "column",
577
- alignItems: "flex-end"
1078
+ alignItems: "flex-end",
1079
+ marginBottom: "8px"
578
1080
  },
579
1081
  messageContainerAssistant: {
580
1082
  display: "flex",
581
1083
  flexDirection: "column",
582
- alignItems: "flex-start"
1084
+ alignItems: "flex-start",
1085
+ marginBottom: "8px",
1086
+ width: "100%",
1087
+ maxWidth: "100%",
1088
+ boxSizing: "border-box"
583
1089
  },
584
1090
  messageBubbleUser: {
585
1091
  backgroundColor: "#111827",
@@ -589,7 +1095,8 @@ var styles = {
589
1095
  padding: "0.5rem 1rem",
590
1096
  fontSize: "0.875rem",
591
1097
  boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
592
- maxWidth: "85%"
1098
+ maxWidth: "85%",
1099
+ textAlign: "left"
593
1100
  },
594
1101
  messageBubbleAssistant: {
595
1102
  backgroundColor: "#f3f4f6",
@@ -599,7 +1106,8 @@ var styles = {
599
1106
  padding: "0.5rem 1rem",
600
1107
  fontSize: "0.875rem",
601
1108
  boxShadow: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
602
- maxWidth: "85%"
1109
+ maxWidth: "85%",
1110
+ textAlign: "left"
603
1111
  },
604
1112
  thinkingIndicator: {
605
1113
  display: "flex",
@@ -681,7 +1189,8 @@ var styles = {
681
1189
  outline: "none",
682
1190
  fontSize: "0.875rem",
683
1191
  color: "#111827",
684
- padding: "0.25rem 0"
1192
+ padding: "0.25rem 0",
1193
+ fontFamily: "inherit"
685
1194
  },
686
1195
  formButton: {
687
1196
  backgroundColor: "transparent",
@@ -694,7 +1203,8 @@ var styles = {
694
1203
  fontWeight: "bold",
695
1204
  border: "none",
696
1205
  cursor: "pointer",
697
- transition: "background-color 0.2s"
1206
+ transition: "background-color 0.2s",
1207
+ fontFamily: "inherit"
698
1208
  },
699
1209
  sendButton: {
700
1210
  backgroundColor: "#AD59FF1A"
@@ -704,90 +1214,297 @@ var styles = {
704
1214
  color: "#9ca3af",
705
1215
  textAlign: "center",
706
1216
  marginTop: "0.75rem"
1217
+ },
1218
+ backdrop: {
1219
+ position: "fixed",
1220
+ top: 0,
1221
+ left: 0,
1222
+ right: 0,
1223
+ bottom: 0,
1224
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
1225
+ backdropFilter: "blur(4px)",
1226
+ zIndex: 1e3
1227
+ },
1228
+ feedbackRow: {
1229
+ display: "flex",
1230
+ alignItems: "center",
1231
+ gap: "0.5rem",
1232
+ marginTop: "0.5rem",
1233
+ marginLeft: "0.75rem"
1234
+ },
1235
+ feedbackButton: {
1236
+ backgroundColor: "transparent",
1237
+ border: "none",
1238
+ cursor: "pointer",
1239
+ padding: "6px",
1240
+ borderRadius: "6px",
1241
+ display: "flex",
1242
+ alignItems: "center",
1243
+ justifyContent: "center",
1244
+ transition: "background-color 0.2s"
1245
+ },
1246
+ warningBanner: {
1247
+ backgroundColor: "#fffbeb",
1248
+ color: "#b45309",
1249
+ border: "1px solid #fde68a",
1250
+ borderRadius: "0.375rem",
1251
+ padding: "0.25rem 0.5rem",
1252
+ fontSize: "0.6875rem",
1253
+ fontWeight: 500,
1254
+ textAlign: "center",
1255
+ margin: "0 0.5rem",
1256
+ flex: 1,
1257
+ display: "flex",
1258
+ alignItems: "center",
1259
+ justifyContent: "center"
1260
+ },
1261
+ insufficientConfigContainer: {
1262
+ flex: 1,
1263
+ display: "flex",
1264
+ flexDirection: "column",
1265
+ alignItems: "center",
1266
+ justifyContent: "center",
1267
+ padding: "2rem",
1268
+ textAlign: "center",
1269
+ backgroundColor: "#fff5f5",
1270
+ color: "#2d3748"
1271
+ },
1272
+ insufficientConfigIconContainer: {
1273
+ backgroundColor: "#fee2e2",
1274
+ padding: "1rem",
1275
+ borderRadius: "50%",
1276
+ marginBottom: "1rem",
1277
+ display: "flex",
1278
+ alignItems: "center",
1279
+ justifyContent: "center",
1280
+ boxShadow: "0 4px 6px -1px rgba(239, 68, 68, 0.1), 0 2px 4px -1px rgba(239, 68, 68, 0.06)"
1281
+ },
1282
+ insufficientConfigTitle: {
1283
+ fontSize: "1.25rem",
1284
+ fontWeight: 700,
1285
+ color: "#991b1b",
1286
+ marginBottom: "0.5rem"
1287
+ },
1288
+ insufficientConfigMessage: {
1289
+ fontSize: "0.875rem",
1290
+ color: "#7f1d1d",
1291
+ marginBottom: "1.5rem",
1292
+ lineHeight: "1.5",
1293
+ maxWidth: "280px"
1294
+ },
1295
+ insufficientConfigDetails: {
1296
+ backgroundColor: "white",
1297
+ border: "1px solid #fee2e2",
1298
+ borderRadius: "0.5rem",
1299
+ padding: "1rem",
1300
+ textAlign: "left",
1301
+ width: "100%",
1302
+ maxWidth: "300px",
1303
+ boxShadow: "0 1px 3px 0 rgba(0, 0, 0, 0.05)"
707
1304
  }
708
1305
  };
1306
+ var ANIMATION_STYLES = `
1307
+ @keyframes sh-fade-in {
1308
+ from {
1309
+ opacity: 0;
1310
+ transform: translate(-50%, -48%) scale(0.96);
1311
+ }
1312
+ to {
1313
+ opacity: 1;
1314
+ transform: translate(-50%, -50%) scale(1);
1315
+ }
1316
+ }
1317
+ @keyframes sh-fade-out {
1318
+ from {
1319
+ opacity: 1;
1320
+ transform: translate(-50%, -50%) scale(1);
1321
+ }
1322
+ to {
1323
+ opacity: 0;
1324
+ transform: translate(-50%, -48%) scale(0.96);
1325
+ }
1326
+ }
1327
+ @keyframes sh-backdrop-fade-in {
1328
+ from {
1329
+ opacity: 0;
1330
+ }
1331
+ to {
1332
+ opacity: 1;
1333
+ }
1334
+ }
1335
+ @keyframes sh-backdrop-fade-out {
1336
+ from {
1337
+ opacity: 1;
1338
+ }
1339
+ to {
1340
+ opacity: 0;
1341
+ }
1342
+ }
1343
+ .sh-dialog-animate {
1344
+ animation: sh-fade-in 0.22s cubic-bezier(0.16, 1, 0.3, 1) forwards;
1345
+ }
1346
+ .sh-dialog-animate-out {
1347
+ animation: sh-fade-out 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
1348
+ }
1349
+ .sh-backdrop-animate {
1350
+ animation: sh-backdrop-fade-in 0.18s ease-out forwards;
1351
+ }
1352
+ .sh-backdrop-animate-out {
1353
+ animation: sh-backdrop-fade-out 0.18s ease-out forwards;
1354
+ }
1355
+ .sh-feedback-btn {
1356
+ color: #a1a1aa;
1357
+ border-radius: 4px;
1358
+ transition: color 0.2s, background-color 0.2s;
1359
+ }
1360
+ .sh-feedback-btn:hover {
1361
+ background-color: #f4f4f5 !important;
1362
+ color: #3f3f46 !important;
1363
+ }
1364
+ .sh-header-btn {
1365
+ transition: all 0.2s;
1366
+ }
1367
+ .sh-header-btn:hover {
1368
+ background-color: #f9fafb !important;
1369
+ border-color: #d1d5db !important;
1370
+ }
1371
+ `;
709
1372
  var TRANSLATIONS = {
710
1373
  newChat: "New Chat",
711
1374
  welcomeToShopPrompter: "Welcome to ShopPrompter",
712
1375
  welcomeDescription: "I am your personal AI shopping assistant. Ask me anything about our products!",
713
1376
  askMeAnything: "Ask me anything...",
714
1377
  thinking: "Thinking...",
715
- showPopularItems: "Show popular items",
716
- compareProducts: "Compare products",
717
- findByBudget: "Find by budget"
1378
+ feedbackError: "We are sorry, but we could not process your feedback. Please try again later."
718
1379
  };
719
1380
  var ICONS = {
720
1381
  chat: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/message-square.svg",
721
1382
  shopprompter: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/bot.svg",
722
1383
  popularitems: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/fire.svg",
723
1384
  compareproducts: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/box.svg",
724
- findbybudget: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/foto.svg",
725
1385
  sendHorizontal: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/send-horizontal.svg"
726
1386
  };
727
1387
  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"
1388
+ var _a, _b, _c, _d;
1389
+ const [input, setInput] = (0, import_react2.useState)(() => "");
1390
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(() => false);
1391
+ const [error, setError] = (0, import_react2.useState)(() => null);
1392
+ const [chatMessages, setChatMessages] = (0, import_react2.useState)(() => []);
1393
+ const [showChat, setShowChat] = (0, import_react2.useState)(() => false);
1394
+ const [isClosing, setIsClosing] = (0, import_react2.useState)(() => false);
1395
+ const [closeTimeout, setCloseTimeout] = (0, import_react2.useState)(() => null);
1396
+ const [service, setService] = (0, import_react2.useState)(() => null);
1397
+ const [agentExperience, setAgentExperience] = (0, import_react2.useState)(() => null);
1398
+ const [animationClass, setAnimationClass] = (0, import_react2.useState)(() => "");
1399
+ const [backdropAnimationClass, setBackdropAnimationClass] = (0, import_react2.useState)(
1400
+ () => ""
735
1401
  );
736
- const [service, setService] = (0, import_react.useState)(() => null);
737
- const [isHeaderButtonHovered, setIsHeaderButtonHovered] = (0, import_react.useState)(
738
- () => false
739
- );
740
- const [agentExperience, setAgentExperience] = (0, import_react.useState)(() => null);
1402
+ function hasToken() {
1403
+ var _a2;
1404
+ const token = props.shopPrompterToken || ((_a2 = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a2.shopPrompterToken);
1405
+ return !!token;
1406
+ }
1407
+ function isConfigInsufficient() {
1408
+ var _a2, _b2;
1409
+ const token = props.shopPrompterToken || ((_a2 = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a2.shopPrompterToken);
1410
+ const apiKey = (_b2 = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _b2.apiKey;
1411
+ return !token && !apiKey;
1412
+ }
1413
+ function showPriceIfEmptyVal() {
1414
+ const val = props.showPriceIfEmpty;
1415
+ if (typeof val === "string") {
1416
+ return val === "true";
1417
+ }
1418
+ return val != null ? val : false;
1419
+ }
1420
+ function visibleFieldsList() {
1421
+ const val = props.visibleFields;
1422
+ if (typeof val === "string") {
1423
+ try {
1424
+ return JSON.parse(val);
1425
+ } catch (e) {
1426
+ return val.split(",").map((s) => s.trim()).filter(Boolean);
1427
+ }
1428
+ }
1429
+ return val || [];
1430
+ }
1431
+ function themeObj() {
1432
+ if (typeof props.theme === "string") {
1433
+ try {
1434
+ return JSON.parse(props.theme);
1435
+ } catch (e) {
1436
+ return {};
1437
+ }
1438
+ }
1439
+ return props.theme || {};
1440
+ }
1441
+ function prompts() {
1442
+ return (agentExperience == null ? void 0 : agentExperience.predefinedPrompts) || [];
1443
+ }
1444
+ function apiConfigObj() {
1445
+ if (typeof props.apiConfig === "string") {
1446
+ try {
1447
+ return JSON.parse(props.apiConfig);
1448
+ } catch (e) {
1449
+ return null;
1450
+ }
1451
+ }
1452
+ return props.apiConfig || null;
1453
+ }
741
1454
  function containerStyle() {
742
1455
  const pos = props.chatPosition || "classic-chatbot";
743
1456
  const isFull = pos === "full-page";
744
- const isBottom = pos === "bottom-sheet";
1457
+ const isDialog = pos === "dialog";
745
1458
  const isClassic = pos === "classic-chatbot";
746
1459
  const isRight = pos === "right-panel";
747
1460
  return {
748
1461
  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",
1462
+ bottom: isClassic ? "1rem" : isDialog ? "auto" : "0",
1463
+ top: isDialog ? "50%" : "auto",
1464
+ right: isClassic || isRight ? "1rem" : isDialog ? "auto" : "0",
1465
+ left: isDialog ? "50%" : isClassic || isRight || isFull ? "auto" : "0",
1466
+ transform: isDialog ? "translate(-50%, -50%)" : "none",
1467
+ width: isFull ? "100%" : isDialog ? "90%" : "24rem",
1468
+ height: isClassic ? "550px" : isDialog ? "700px" : isFull ? "600px" : "100%",
1469
+ maxWidth: isDialog ? "900px" : "none",
1470
+ maxHeight: isDialog ? "90vh" : "none",
1471
+ zIndex: isDialog ? 1001 : isClassic || isRight ? 1001 : 50,
1472
+ backgroundColor: themeObj().mainBackgroundColor || "white",
758
1473
  display: "flex",
759
1474
  flexDirection: "column",
760
1475
  overflow: "hidden",
761
1476
  borderRadius: isFull ? "0" : "0.5rem",
762
1477
  border: isFull ? "none" : "1px solid #e5e7eb",
763
- boxShadow: isFull ? "none" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
1478
+ boxShadow: isFull ? "none" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
1479
+ fontFamily: themeObj().fontFamily || void 0
764
1480
  };
765
1481
  }
766
1482
  function containerClass() {
767
1483
  const pos = props.chatPosition || "classic-chatbot";
768
1484
  if (pos === "classic-chatbot") return "sh-classic";
769
1485
  if (pos === "right-panel") return "sh-right";
770
- if (pos === "bottom-sheet") return "sh-bottom";
1486
+ if (pos === "dialog") {
1487
+ return "sh-dialog " + animationClass;
1488
+ }
771
1489
  return "sh-full";
772
1490
  }
773
1491
  function messages() {
774
- return chatMessages.map((msg) => ({
775
- ...msg,
776
- safeProductSkus: msg.productSkus || []
777
- }));
1492
+ return chatMessages;
1493
+ }
1494
+ function parseMarkdown(content) {
1495
+ if (!content) return "";
1496
+ return String(import_marked.marked.parse(content));
778
1497
  }
779
1498
  function showWelcome() {
780
1499
  return chatMessages.length === 0;
781
1500
  }
782
- function getProductImageUrl(sku) {
783
- return "https://placehold.co/100x100?text=" + sku;
1501
+ function getShowProducts(message) {
1502
+ return message.productSkus && message.productSkus.length > 0;
784
1503
  }
785
- function getProductLink(sku) {
786
- return "/product/" + sku;
787
- }
788
- function handleSend() {
789
- if (!input.trim() || isLoading) return;
790
- const userQuery = input;
1504
+ function handleSend(overrideQuery) {
1505
+ const actualQuery = overrideQuery || input;
1506
+ if (!actualQuery.trim() || isLoading) return;
1507
+ const userQuery = actualQuery;
791
1508
  setInput("");
792
1509
  const userMsg = {
793
1510
  id: Date.now().toString() + "-user",
@@ -795,30 +1512,45 @@ function ShopPrompter(props) {
795
1512
  content: userQuery,
796
1513
  productSkus: []
797
1514
  };
798
- setChatMessages([...chatMessages, userMsg]);
799
1515
  const assistantMsg = {
800
1516
  id: Date.now().toString() + "-assistant",
801
1517
  role: "assistant",
802
1518
  content: "",
803
1519
  productSkus: []
804
1520
  };
805
- setChatMessages([...chatMessages, assistantMsg]);
1521
+ let currentMessages = [...chatMessages, userMsg, assistantMsg];
1522
+ setChatMessages(currentMessages);
1523
+ setTimeout(() => {
1524
+ const inputEl = document.getElementById("shop-prompter-input");
1525
+ if (inputEl) {
1526
+ inputEl.value = "";
1527
+ inputEl.focus();
1528
+ }
1529
+ }, 0);
806
1530
  service == null ? void 0 : service.sendMessage(
807
1531
  userQuery,
808
1532
  {
809
1533
  onTextUpdate: (text) => {
810
- const updatedMessages = [...chatMessages];
1534
+ const updatedMessages = [...currentMessages];
811
1535
  const lastMsg = updatedMessages[updatedMessages.length - 1];
812
1536
  if (lastMsg) {
813
- lastMsg.content = text;
1537
+ updatedMessages[updatedMessages.length - 1] = {
1538
+ ...lastMsg,
1539
+ content: text
1540
+ };
1541
+ currentMessages = updatedMessages;
814
1542
  setChatMessages(updatedMessages);
815
1543
  }
816
1544
  },
817
1545
  onProductSkus: (skus) => {
818
- const updatedMessages = [...chatMessages];
1546
+ const updatedMessages = [...currentMessages];
819
1547
  const lastMsg = updatedMessages[updatedMessages.length - 1];
820
1548
  if (lastMsg) {
821
- lastMsg.productSkus = skus;
1549
+ updatedMessages[updatedMessages.length - 1] = {
1550
+ ...lastMsg,
1551
+ productSkus: skus
1552
+ };
1553
+ currentMessages = updatedMessages;
822
1554
  setChatMessages(updatedMessages);
823
1555
  }
824
1556
  },
@@ -832,29 +1564,63 @@ function ShopPrompter(props) {
832
1564
  if (props.onCartOperation) {
833
1565
  props.onCartOperation(ops);
834
1566
  }
1567
+ dispatchCartOperation(ops);
835
1568
  }
836
1569
  },
837
1570
  props.cart || []
838
1571
  );
839
1572
  }
1573
+ function dispatchCartOperation(ops) {
1574
+ if (typeof window !== "undefined") {
1575
+ const root = typeof self !== "undefined" && self && "dispatchEvent" in self && !(self instanceof Window) ? self : null;
1576
+ if (root) {
1577
+ root.dispatchEvent(
1578
+ new CustomEvent("cartOperation", {
1579
+ detail: ops
1580
+ })
1581
+ );
1582
+ }
1583
+ }
1584
+ }
840
1585
  function toggleChat() {
841
- setShowChat(!showChat);
842
- if (!showChat && props.onClose) {
843
- props.onClose();
1586
+ if (showChat) {
1587
+ setIsClosing(true);
1588
+ setAnimationClass("sh-dialog-animate-out");
1589
+ setBackdropAnimationClass("sh-backdrop-animate-out");
1590
+ if (closeTimeout) {
1591
+ clearTimeout(closeTimeout);
1592
+ }
1593
+ setCloseTimeout(
1594
+ setTimeout(() => {
1595
+ setShowChat(false);
1596
+ setIsClosing(false);
1597
+ setAnimationClass("");
1598
+ setBackdropAnimationClass("");
1599
+ setCloseTimeout(null);
1600
+ if (props.onClose) {
1601
+ props.onClose();
1602
+ }
1603
+ }, 200)
1604
+ );
1605
+ } else {
1606
+ if (closeTimeout) {
1607
+ clearTimeout(closeTimeout);
1608
+ setCloseTimeout(null);
1609
+ }
1610
+ setShowChat(true);
1611
+ setIsClosing(false);
1612
+ setAnimationClass("sh-dialog-animate");
1613
+ setBackdropAnimationClass("sh-backdrop-animate");
1614
+ setTimeout(() => {
1615
+ setAnimationClass("");
1616
+ setBackdropAnimationClass("");
1617
+ }, 250);
844
1618
  }
845
1619
  }
846
1620
  function handleNewChat() {
847
1621
  setChatMessages([]);
848
1622
  service == null ? void 0 : service.resetSession();
849
1623
  }
850
- function onPopularItemsClick() {
851
- setInput(TRANSLATIONS.showPopularItems);
852
- handleSend();
853
- }
854
- function onCompareProductsClick() {
855
- setInput(TRANSLATIONS.compareProducts);
856
- handleSend();
857
- }
858
1624
  function onInputChange(event) {
859
1625
  setInput(event.target.value);
860
1626
  }
@@ -863,49 +1629,196 @@ function ShopPrompter(props) {
863
1629
  handleSend();
864
1630
  }
865
1631
  }
866
- function onHeaderButtonMouseEnter() {
867
- setIsHeaderButtonHovered(true);
1632
+ function handleTriggerClick(e) {
1633
+ if (props.chatPosition !== "dialog") return;
1634
+ if (!props.dialogTrigger) return;
1635
+ const isTargetClicked = typeof props.dialogTrigger === "string" ? e.target.closest(props.dialogTrigger) : (() => {
1636
+ let target = null;
1637
+ if (typeof props.dialogTrigger === "object") {
1638
+ if ("current" in props.dialogTrigger) {
1639
+ target = props.dialogTrigger.current;
1640
+ } else {
1641
+ target = props.dialogTrigger;
1642
+ }
1643
+ }
1644
+ return target && target.contains && target.contains(e.target);
1645
+ })();
1646
+ if (isTargetClicked) {
1647
+ if (closeTimeout) {
1648
+ clearTimeout(closeTimeout);
1649
+ setCloseTimeout(null);
1650
+ }
1651
+ setShowChat(true);
1652
+ setIsClosing(false);
1653
+ setAnimationClass("sh-dialog-animate");
1654
+ setBackdropAnimationClass("sh-backdrop-animate");
1655
+ setTimeout(() => {
1656
+ setAnimationClass("");
1657
+ setBackdropAnimationClass("");
1658
+ }, 250);
1659
+ }
868
1660
  }
869
- function onHeaderButtonMouseLeave() {
870
- setIsHeaderButtonHovered(false);
1661
+ function loadCustomFont(fontFamily) {
1662
+ if (!fontFamily || typeof window === "undefined") return;
1663
+ const systemFonts = [
1664
+ "sans-serif",
1665
+ "serif",
1666
+ "monospace",
1667
+ "cursive",
1668
+ "fantasy",
1669
+ "system-ui",
1670
+ "-apple-system",
1671
+ "blinkmacsystemfont",
1672
+ "segoe ui",
1673
+ "roboto",
1674
+ "helvetica",
1675
+ "arial",
1676
+ "inherit"
1677
+ ];
1678
+ const cleanFont = fontFamily.split(",")[0].trim().replace(new RegExp(`['"]`, "g"), "");
1679
+ if (!cleanFont || systemFonts.includes(cleanFont.toLowerCase())) return;
1680
+ const linkId = `shopprompter-font-${cleanFont.toLowerCase().replace(new RegExp("\\s+", "g"), "-")}`;
1681
+ if (document.getElementById(linkId)) return;
1682
+ const link = document.createElement("link");
1683
+ link.id = linkId;
1684
+ link.rel = "stylesheet";
1685
+ const fontNameUrl = cleanFont.replace(new RegExp("\\s+", "g"), "+");
1686
+ link.href = `https://fonts.googleapis.com/css2?family=${fontNameUrl}:wght@400;500;600;700&display=swap`;
1687
+ document.head.appendChild(link);
871
1688
  }
872
- function doSomethingAsync() {
1689
+ function loadAgentExperience() {
873
1690
  void (async function() {
874
- console.log("## ~ ShopPrompter ~ state.service:", service);
875
1691
  if (!service) {
876
- console.warn("Service not initialized yet");
1692
+ console.warn(
1693
+ "Service not initialized yet! Cannot load AgentExperience."
1694
+ );
877
1695
  return;
878
1696
  }
879
1697
  const response = await (service == null ? void 0 : service.getAgentExperience());
880
- console.log("## ~ ShopPrompter ~ response:", response);
881
1698
  setAgentExperience(response);
882
1699
  })();
883
1700
  }
884
- (0, import_react.useEffect)(() => {
885
- const shopPrompterService = new ShopPrompterService();
886
- setService(shopPrompterService);
1701
+ function handleFeedback(messageId, messageContent, newFeedback) {
1702
+ const msg = chatMessages.find((m) => m.id === messageId);
1703
+ if (!msg) return;
1704
+ const currentFeedback = msg.feedback;
1705
+ const targetFeedback = currentFeedback === newFeedback ? "clear" : newFeedback;
1706
+ const oldMessages = [...chatMessages];
1707
+ setChatMessages(
1708
+ chatMessages.map((m) => {
1709
+ if (m.id === messageId) {
1710
+ return {
1711
+ ...m,
1712
+ feedback: targetFeedback === "clear" ? null : targetFeedback
1713
+ };
1714
+ }
1715
+ return m;
1716
+ })
1717
+ );
1718
+ setError(null);
1719
+ service == null ? void 0 : service.sendFeedback(messageId, messageContent, targetFeedback).catch((err) => {
1720
+ setChatMessages(oldMessages);
1721
+ setError((err == null ? void 0 : err.message) || TRANSLATIONS.feedbackError);
1722
+ });
1723
+ }
1724
+ function canShowFeedback(message) {
1725
+ if (message.role !== "assistant") return false;
1726
+ if (!message.content) return false;
1727
+ const lastMsg = chatMessages[chatMessages.length - 1];
1728
+ if (lastMsg && lastMsg.id === message.id && isLoading) {
1729
+ return false;
1730
+ }
1731
+ return true;
1732
+ }
1733
+ (0, import_react2.useEffect)(() => {
1734
+ if (typeof window !== "undefined" && !document.getElementById("lottie-player-script")) {
1735
+ const script = document.createElement("script");
1736
+ script.id = "lottie-player-script";
1737
+ script.src = "https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player";
1738
+ document.head.appendChild(script);
1739
+ }
1740
+ if (themeObj().fontFamily) {
1741
+ loadCustomFont(themeObj().fontFamily);
1742
+ }
1743
+ if (apiConfigObj()) {
1744
+ if (!isConfigInsufficient()) {
1745
+ const apiConfig = {
1746
+ ...apiConfigObj(),
1747
+ shopPrompterToken: props.shopPrompterToken || apiConfigObj().shopPrompterToken
1748
+ };
1749
+ const service2 = new ShopPrompterService(apiConfig);
1750
+ setService(service2);
1751
+ const savedMessages = service2.loadMessages();
1752
+ if (savedMessages.length > 0) {
1753
+ setChatMessages(savedMessages);
1754
+ }
1755
+ }
1756
+ } else {
1757
+ console.error("ShopPrompter: apiConfig prop is required!");
1758
+ }
1759
+ if ((props == null ? void 0 : props.chatPosition) === "right-panel" || (props == null ? void 0 : props.chatPosition) === "full-page") {
1760
+ setShowChat(true);
1761
+ }
1762
+ if (typeof window !== "undefined") {
1763
+ document.addEventListener("click", handleTriggerClick);
1764
+ }
887
1765
  }, []);
888
- (0, import_react.useEffect)(() => {
1766
+ (0, import_react2.useEffect)(() => {
889
1767
  if (service && !agentExperience) {
890
- doSomethingAsync();
891
- }
892
- if (agentExperience) {
893
- console.log("## ~ ShopPrompter ~ agentExperience updated:", {
894
- greeting: agentExperience.greeting,
895
- agentLogoUrl: agentExperience.agentLogoUrl
896
- });
1768
+ loadAgentExperience();
897
1769
  }
898
1770
  }, [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)(
1771
+ (0, import_react2.useEffect)(() => {
1772
+ if (themeObj().fontFamily) {
1773
+ loadCustomFont(themeObj().fontFamily);
1774
+ }
1775
+ }, [themeObj().fontFamily || ""]);
1776
+ (0, import_react2.useEffect)(() => {
1777
+ if ((props == null ? void 0 : props.chatPosition) === "right-panel" || (props == null ? void 0 : props.chatPosition) === "full-page") {
1778
+ setShowChat(true);
1779
+ } else if ((props == null ? void 0 : props.chatPosition) === "dialog" || (props == null ? void 0 : props.chatPosition) === "classic-chatbot") {
1780
+ setShowChat(false);
1781
+ setIsClosing(false);
1782
+ setAnimationClass("");
1783
+ setBackdropAnimationClass("");
1784
+ }
1785
+ }, [(props == null ? void 0 : props.chatPosition) || ""]);
1786
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "shopprompter-sdk", children: [
1787
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { dangerouslySetInnerHTML: { __html: ANIMATION_STYLES } }),
1788
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1789
+ "div",
1790
+ {
1791
+ onClick: (e) => toggleChat(),
1792
+ style: {
1793
+ ...styles2.backdrop,
1794
+ display: props.chatPosition === "dialog" && (showChat || isClosing) ? "block" : "none"
1795
+ },
1796
+ className: backdropAnimationClass
1797
+ }
1798
+ ),
1799
+ props.chatPosition === "classic-chatbot" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: !showChat ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
901
1800
  "button",
902
1801
  {
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
1802
  onClick: (e) => toggleChat(),
905
1803
  style: {
906
- boxShadow: "0 0 0 8px rgba(37, 99, 235, 0.2)"
1804
+ position: "fixed",
1805
+ bottom: "1.5rem",
1806
+ right: "1.5rem",
1807
+ width: "4rem",
1808
+ height: "4rem",
1809
+ backgroundColor: themeObj().actionColor || "#2563eb",
1810
+ borderRadius: "9999px",
1811
+ zIndex: 50,
1812
+ display: "flex",
1813
+ alignItems: "center",
1814
+ justifyContent: "center",
1815
+ transition: "background-color 0.2s",
1816
+ border: "none",
1817
+ cursor: "pointer",
1818
+ 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)",
1819
+ fontFamily: themeObj().fontFamily || void 0
907
1820
  },
908
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1821
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
909
1822
  "img",
910
1823
  {
911
1824
  alt: "Chat",
@@ -918,259 +1831,406 @@ function ShopPrompter(props) {
918
1831
  )
919
1832
  }
920
1833
  ) : 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"
1834
+ showChat || isClosing ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: containerStyle(), className: containerClass(), children: [
1835
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1836
+ "div",
1837
+ {
1838
+ style: {
1839
+ ...styles2.header,
1840
+ backgroundColor: themeObj().headerBackgroundColor || "transparent"
1841
+ },
1842
+ children: [
1843
+ themeObj().showAgentName !== false ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.subHeaderContainer, children: [
1844
+ (agentExperience == null ? void 0 : agentExperience.agentLogoUrl) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1845
+ "img",
1846
+ {
1847
+ src: agentExperience.agentLogoUrl,
1848
+ alt: agentExperience.agentName,
1849
+ style: {
1850
+ width: "24px",
1851
+ height: "24px",
1852
+ borderRadius: "4px",
1853
+ objectFit: "cover"
952
1854
  }
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",
1855
+ }
1856
+ ) : null,
1857
+ (agentExperience == null ? void 0 : agentExperience.agentName) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: styles2.headerText, children: agentExperience.agentName }) : null
1858
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles2.subHeaderContainer }) }),
1859
+ !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,
1860
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.subHeaderContainer, children: [
1861
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1862
+ "button",
1863
+ {
1864
+ className: "sh-header-btn",
1865
+ onClick: (e) => handleNewChat(),
1866
+ style: styles2.headerButton,
1867
+ children: TRANSLATIONS.newChat
1868
+ }
1869
+ ),
1870
+ props.chatPosition === "classic-chatbot" || props.chatPosition === "right-panel" || props.chatPosition === "dialog" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1871
+ "button",
1872
+ {
1873
+ onClick: (e) => toggleChat(),
1874
+ style: styles2.ButtonSheetButton,
1875
+ children: "\xD7"
1876
+ }
1877
+ ) : null
1878
+ ] })
1879
+ ]
1880
+ }
1881
+ ),
1882
+ isConfigInsufficient() ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.insufficientConfigContainer, children: [
1883
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles2.insufficientConfigIconContainer, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1884
+ "svg",
1885
+ {
1886
+ width: "48",
1887
+ height: "48",
1888
+ viewBox: "0 0 24 24",
1889
+ fill: "none",
1890
+ stroke: "currentColor",
1891
+ strokeWidth: "2",
1892
+ strokeLinecap: "round",
1893
+ strokeLinejoin: "round",
1894
+ style: {
1895
+ color: "#ef4444"
1896
+ },
1897
+ children: [
1898
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }),
1899
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7 11V7a5 5 0 0 1 9.9-1" })
1900
+ ]
1901
+ }
1902
+ ) }),
1903
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1904
+ "h3",
1905
+ {
1906
+ style: {
1907
+ ...styles2.insufficientConfigTitle,
1908
+ fontFamily: themeObj().fontFamily || void 0
1909
+ },
1910
+ children: "Configuration Error"
1911
+ }
1912
+ ),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1914
+ "p",
1915
+ {
1916
+ style: {
1917
+ ...styles2.insufficientConfigMessage,
1918
+ fontFamily: themeObj().fontFamily || void 0
1919
+ },
1920
+ children: "ShopPrompter requires a secure token or API key to initialize. Please check your setup."
1921
+ }
1922
+ ),
1923
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1924
+ "div",
1925
+ {
1926
+ style: {
1927
+ ...styles2.insufficientConfigDetails,
1928
+ fontFamily: themeObj().fontFamily || void 0
1929
+ },
1930
+ children: [
1931
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1932
+ "div",
1933
+ {
1934
+ style: {
1935
+ fontWeight: 600,
1936
+ marginBottom: "0.25rem"
1937
+ },
1938
+ children: "Missing Parameters:"
1939
+ }
1940
+ ),
1941
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1942
+ "div",
1943
+ {
1944
+ style: {
1945
+ display: "flex",
1946
+ flexDirection: "column",
1947
+ gap: "0.25rem",
1948
+ fontFamily: "monospace",
1949
+ fontSize: "0.75rem"
1950
+ },
1951
+ children: [
1952
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1953
+ "span",
1954
+ {
1955
+ style: {
1956
+ color: "#ef4444"
1957
+ },
1958
+ children: "\u2717 shopPrompterToken (not found)"
1959
+ }
1960
+ ),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1962
+ "span",
1963
+ {
1964
+ style: {
1965
+ color: "#ef4444"
1966
+ },
1967
+ children: "\u2717 apiConfig.apiKey (not found)"
1968
+ }
1969
+ )
1970
+ ]
1971
+ }
1972
+ )
1973
+ ]
1974
+ }
1975
+ )
1976
+ ] }) : null,
1977
+ !isConfigInsufficient() ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1978
+ "div",
1979
+ {
1980
+ style: {
1981
+ display: "flex",
1982
+ flexDirection: "column",
1983
+ flex: 1,
1984
+ overflow: "hidden"
1985
+ },
1986
+ children: [
1987
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1988
+ "div",
1989
+ {
1990
+ id: "shop-prompter-chat-container",
1991
+ style: {
1992
+ ...styles2.chatContainer,
1993
+ backgroundColor: themeObj().mainBackgroundColor || styles2.chatContainer.backgroundColor
1994
+ },
1995
+ children: [
1996
+ showWelcome() ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.welcomeContainer, children: [
1997
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1998
+ "img",
1999
+ {
2000
+ alt: "ShopPrompter",
2001
+ src: (agentExperience == null ? void 0 : agentExperience.agentLogoUrl) ? agentExperience.agentLogoUrl : ICONS.shopprompter,
2002
+ style: {
2003
+ width: "64px",
2004
+ height: "64px",
2005
+ marginBottom: "24px",
2006
+ borderRadius: "12px",
2007
+ objectFit: "cover"
2008
+ }
2009
+ }
2010
+ ),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2012
+ "h3",
2013
+ {
2014
+ style: {
2015
+ ...styles2.welcomeTitle,
2016
+ fontFamily: themeObj().fontFamily || styles2.welcomeTitle.fontFamily
2017
+ },
2018
+ children: ((_b = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _b.title) || TRANSLATIONS.welcomeToShopPrompter
2019
+ }
2020
+ ),
2021
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2022
+ "p",
2023
+ {
2024
+ style: {
2025
+ ...styles2.welcomeDescription,
2026
+ fontFamily: themeObj().fontFamily || styles2.welcomeDescription.fontFamily
2027
+ },
2028
+ children: ((_c = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _c.description) || TRANSLATIONS.welcomeDescription
2029
+ }
2030
+ ),
2031
+ /* @__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)(
2032
+ "button",
2033
+ {
2034
+ style: styles2.button,
2035
+ onClick: (event) => {
2036
+ setInput(item.prompt);
2037
+ handleSend(item.prompt);
2038
+ },
2039
+ children: item.prompt
2040
+ },
2041
+ item.prompt
2042
+ )) })
2043
+ ] }) : null,
2044
+ !showWelcome() ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2045
+ "div",
1016
2046
  {
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
- ]
2047
+ style: {
2048
+ width: "100%"
2049
+ },
2050
+ children: chatMessages == null ? void 0 : chatMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
2051
+ message.role === "user" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles2.messageContainerUser, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2052
+ "div",
2053
+ {
2054
+ style: {
2055
+ ...styles2.messageBubbleUser,
2056
+ backgroundColor: themeObj().userMessageBackgroundColor || styles2.messageBubbleUser.backgroundColor
2057
+ },
2058
+ children: message.content
2059
+ }
2060
+ ) }) : null,
2061
+ message.role === "assistant" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.messageContainerAssistant, children: [
2062
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2063
+ "div",
2064
+ {
2065
+ style: {
2066
+ ...styles2.messageBubbleAssistant,
2067
+ backgroundColor: themeObj().assistantMessageBackgroundColor || styles2.messageBubbleAssistant.backgroundColor
2068
+ },
2069
+ children: [
2070
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2071
+ "div",
2072
+ {
2073
+ dangerouslySetInnerHTML: {
2074
+ __html: parseMarkdown(message.content)
2075
+ }
2076
+ }
2077
+ ),
2078
+ !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)(
2079
+ "lottie-player",
2080
+ {
2081
+ background: "transparent",
2082
+ speed: "1",
2083
+ src: agentExperience.loadingIndicatorUrl,
2084
+ style: {
2085
+ width: "40px",
2086
+ height: "40px"
2087
+ },
2088
+ loop: true,
2089
+ autoplay: true
2090
+ }
2091
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles2.thinkingIndicator, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2092
+ "svg",
2093
+ {
2094
+ width: "24",
2095
+ height: "24",
2096
+ viewBox: "0 0 24 24",
2097
+ fill: "none",
2098
+ stroke: "currentColor",
2099
+ strokeWidth: "2",
2100
+ strokeLinecap: "round",
2101
+ strokeLinejoin: "round",
2102
+ style: {
2103
+ color: "#6b7280"
2104
+ },
2105
+ children: [
2106
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: THINKING_SPINNER }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2108
+ "animateTransform",
2109
+ {
2110
+ attributeName: "transform",
2111
+ type: "rotate",
2112
+ from: "0 12 12",
2113
+ to: "360 12 12",
2114
+ dur: "1s",
2115
+ repeatCount: "indefinite"
2116
+ }
2117
+ )
2118
+ ]
2119
+ }
2120
+ ) }) }) : null
2121
+ ]
2122
+ }
2123
+ ),
2124
+ canShowFeedback(message) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.feedbackRow, children: [
2125
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2126
+ "button",
2127
+ {
2128
+ className: "sh-feedback-btn",
2129
+ onClick: (event) => handleFeedback(
2130
+ message.id,
2131
+ message.content,
2132
+ "upvote"
2133
+ ),
2134
+ style: styles2.feedbackButton,
2135
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2136
+ thumbs_up_icon_component_default,
2137
+ {
2138
+ fill: message.feedback === "upvote" ? themeObj().actionColor || "#2563eb" : "none",
2139
+ stroke: message.feedback === "upvote" ? themeObj().actionColor || "#2563eb" : "currentColor"
2140
+ }
2141
+ )
2142
+ }
2143
+ ),
2144
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2145
+ "button",
2146
+ {
2147
+ className: "sh-feedback-btn",
2148
+ onClick: (event) => handleFeedback(
2149
+ message.id,
2150
+ message.content,
2151
+ "downvote"
2152
+ ),
2153
+ style: styles2.feedbackButton,
2154
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2155
+ thumbs_down_icon_component_default,
2156
+ {
2157
+ fill: message.feedback === "downvote" ? themeObj().actionColor || "#2563eb" : "none",
2158
+ stroke: message.feedback === "downvote" ? themeObj().actionColor || "#2563eb" : "currentColor"
2159
+ }
2160
+ )
2161
+ }
2162
+ )
2163
+ ] }) : null,
2164
+ getShowProducts(message) ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2165
+ product_card_list_component_default,
2166
+ {
2167
+ skus: message.productSkus,
2168
+ defaultLocale: props.defaultLocale,
2169
+ showPriceIfEmpty: showPriceIfEmptyVal(),
2170
+ visibleFields: visibleFieldsList()
2171
+ }
2172
+ ) : null
2173
+ ] }) : null
2174
+ ] }, message.id))
1030
2175
  }
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
2176
+ ) : null,
2177
+ error ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.errorContainer, children: [
2178
+ "Error: ",
2179
+ error
2180
+ ] }) : null
2181
+ ]
1085
2182
  }
1086
2183
  ),
1087
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1088
- "button",
2184
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2185
+ "div",
1089
2186
  {
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%"
2187
+ style: {
2188
+ ...styles2.inputSection,
2189
+ backgroundColor: themeObj().mainBackgroundColor || styles2.inputSection.backgroundColor
2190
+ },
2191
+ children: [
2192
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles2.inputWrapper, children: [
2193
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2194
+ "input",
2195
+ {
2196
+ id: "shop-prompter-input",
2197
+ type: "text",
2198
+ style: styles2.input,
2199
+ placeholder: (agentExperience == null ? void 0 : agentExperience.hintText) || TRANSLATIONS.askMeAnything,
2200
+ value: input,
2201
+ onInput: (e) => onInputChange(e),
2202
+ onKeyDown: (e) => onInputKeyDown(e)
1122
2203
  }
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",
2204
+ ),
2205
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2206
+ "button",
1129
2207
  {
1130
- href: getProductLink(sku),
1131
- style: styles.productLink,
1132
- children: "VIEW DETAILS"
2208
+ onClick: (e) => handleSend(),
2209
+ style: {
2210
+ ...styles2.formButton,
2211
+ ...styles2.sendButton,
2212
+ backgroundColor: themeObj().actionColor || styles2.sendButton.backgroundColor
2213
+ },
2214
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2215
+ "img",
2216
+ {
2217
+ alt: "Send",
2218
+ src: ICONS.sendHorizontal,
2219
+ style: {
2220
+ padding: "4px"
2221
+ }
2222
+ }
2223
+ )
1133
2224
  }
1134
2225
  )
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
- ] })
2226
+ ] }),
2227
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: styles2.disclaimer, children: "AI content may be inaccurate." })
2228
+ ]
2229
+ }
2230
+ )
2231
+ ]
2232
+ }
2233
+ ) : null
1174
2234
  ] }) : null
1175
2235
  ] });
1176
2236
  }