@xapp/chat-widget 1.78.1 → 1.79.1

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.
Files changed (33) hide show
  1. package/dist/App.d.ts +0 -0
  2. package/dist/components/ChatButton/ChatButton.d.ts +0 -0
  3. package/dist/components/ChatFooter/ChatFooter.d.ts +0 -0
  4. package/dist/components/ChatFooter/ChatFooter.stories.d.ts +3 -0
  5. package/dist/components/ChatWidget/ChatWidget.d.ts +0 -0
  6. package/dist/components/ChatWidget/ChatWidget.stories.d.ts +6 -0
  7. package/dist/components/ChatWidget/ChatWidget.test.d.ts +1 -0
  8. package/dist/components/ChatWidget/ChatWidgetContainer.d.ts +0 -0
  9. package/dist/components/ChatWidget/ChatWidgetEnv.stories.d.ts +1 -0
  10. package/dist/components/ErrorOverlay/ErrorOverlay.d.ts +0 -0
  11. package/dist/components/ErrorOverlay/ErrorOverlay.stories.d.ts +8 -0
  12. package/dist/components/ErrorOverlay/index.d.ts +0 -0
  13. package/dist/components/Input/Input.d.ts +0 -0
  14. package/dist/components/Input/Input.stories.d.ts +7 -3
  15. package/dist/components/SendButton/SendButton.d.ts +0 -0
  16. package/dist/components/SendButton/SendButton.stories.d.ts +8 -4
  17. package/dist/index.css +1 -1
  18. package/dist/index.es.js +581 -96
  19. package/dist/index.es.js.map +1 -1
  20. package/dist/index.js +581 -96
  21. package/dist/index.js.map +1 -1
  22. package/dist/store/ChatAction.d.ts +0 -0
  23. package/dist/store/ChatState.d.ts +0 -0
  24. package/dist/store/DefaultState.d.ts +0 -0
  25. package/dist/store/actions/index.d.ts +0 -0
  26. package/dist/store/actions/toggleDebugMode.d.ts +0 -0
  27. package/dist/xapp/StentorRouterChat.d.ts +0 -0
  28. package/dist/xapp/XappChat.d.ts +0 -0
  29. package/dist/xapp/__tests__/StentorRouterChat.test.d.ts +2 -0
  30. package/dist/xapp-chat-widget.css +1 -1
  31. package/dist/xapp-chat-widget.js +4 -4
  32. package/dist/xapp-chat-widget.js.map +1 -1
  33. package/package.json +10 -10
package/dist/index.es.js CHANGED
@@ -305,6 +305,27 @@ function getTimeAgo(date) {
305
305
  }
306
306
 
307
307
  var EMAIL_REGEX = "^\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$";
308
+ // Initialize log level from localStorage on module load
309
+ var STORAGE_KEY = 'xaLogLevel';
310
+ var storedLogLevel = localStorage.getItem(STORAGE_KEY);
311
+ if (storedLogLevel) {
312
+ window.xaLogLevel = storedLogLevel;
313
+ }
314
+ // Override the setter to persist to localStorage
315
+ Object.defineProperty(window, 'xaLogLevel', {
316
+ get: function () {
317
+ return this._xaLogLevel;
318
+ },
319
+ set: function (value) {
320
+ this._xaLogLevel = value;
321
+ if (value) {
322
+ localStorage.setItem(STORAGE_KEY, value);
323
+ }
324
+ else {
325
+ localStorage.removeItem(STORAGE_KEY);
326
+ }
327
+ }
328
+ });
308
329
  // Returns current timestamp
309
330
  function getCurrentDateString() {
310
331
  return (new Date()).toISOString() + " ::";
@@ -604,7 +625,7 @@ function resize(vec, length) {
604
625
  return mul(vec, length / currentLength);
605
626
  }
606
627
  function rotateZ(vec, angle) {
607
- var rad = angle * Math.PI / 180;
628
+ var rad = (angle * Math.PI) / 180;
608
629
  var ca = Math.cos(rad);
609
630
  var sa = Math.sin(rad);
610
631
  var resx = vec.x * ca + vec.y * sa;
@@ -621,9 +642,9 @@ function intersectLineEllipsis(ellipsis, line) {
621
642
  var ry = ellipsis.radius.y;
622
643
  var rx2 = rx * rx;
623
644
  var ry2 = ry * ry;
624
- var a = (kx * kx / rx2 + ky * ky / ry2);
625
- var b = (2 * kx * sx / rx2 + 2 * ky * sy / ry2);
626
- var c = (sx * sx / rx2 + sy * sy / ry2 - 1);
645
+ var a = (kx * kx) / rx2 + (ky * ky) / ry2;
646
+ var b = (2 * kx * sx) / rx2 + (2 * ky * sy) / ry2;
647
+ var c = (sx * sx) / rx2 + (sy * sy) / ry2 - 1;
627
648
  var d2 = b * b - 4 * a * c;
628
649
  if (d2 >= 0) {
629
650
  var d = Math.sqrt(d2);
@@ -642,10 +663,13 @@ function intersectLineEllipsis(ellipsis, line) {
642
663
  return line.start;
643
664
  }
644
665
  function getTailSvgPath$1(props, viewport) {
645
- var baseAngleRad = props.direction * Math.PI / 180;
666
+ var baseAngleRad = (props.direction * Math.PI) / 180;
646
667
  var radius = { x: props.width / 2, y: props.height / 2 };
647
668
  var center = { x: viewport.x / 2, y: viewport.y / 2 };
648
- var intersectionRel = { x: radius.x * Math.cos(baseAngleRad), y: radius.y * Math.sin(baseAngleRad) };
669
+ var intersectionRel = {
670
+ x: radius.x * Math.cos(baseAngleRad),
671
+ y: radius.y * Math.sin(baseAngleRad),
672
+ };
649
673
  var farRel = resize(intersectionRel, len(intersectionRel) + props.length);
650
674
  var far = add$1(farRel, center);
651
675
  var direction = sub$1(intersectionRel, farRel);
@@ -654,15 +678,15 @@ function getTailSvgPath$1(props, viewport) {
654
678
  var rightDirection = rotateZ(direction, -angle / 2);
655
679
  var ellipsis = {
656
680
  center: center,
657
- radius: radius
681
+ radius: radius,
658
682
  };
659
683
  var left = intersectLineEllipsis(ellipsis, {
660
684
  start: far,
661
- direction: leftDirection
685
+ direction: leftDirection,
662
686
  });
663
687
  var right = intersectLineEllipsis(ellipsis, {
664
688
  start: far,
665
- direction: rightDirection
689
+ direction: rightDirection,
666
690
  });
667
691
  return "m ".concat(far.x, " ").concat(far.y, " L ").concat(left.x, " ").concat(left.y, " L ").concat(right.x, " ").concat(right.y, " z");
668
692
  }
@@ -670,9 +694,9 @@ var CtaBubbleTail = function (props) {
670
694
  var _a, _b;
671
695
  var _c = useDimensions(), ref = _c[0], rect = _c[1];
672
696
  var viewPort = { x: (_a = rect === null || rect === void 0 ? void 0 : rect.width) !== null && _a !== void 0 ? _a : 0, y: (_b = rect === null || rect === void 0 ? void 0 : rect.height) !== null && _b !== void 0 ? _b : 0 };
673
- return React$1.createElement("div", { ref: ref, className: "cta-bubble__tail" },
697
+ return (React$1.createElement("div", { ref: ref, className: "cta-bubble__tail" },
674
698
  React$1.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 ".concat(viewPort.x, " ").concat(viewPort.y) },
675
- React$1.createElement("path", { d: getTailSvgPath$1(props, viewPort), fill: "currentColor" })));
699
+ React$1.createElement("path", { d: getTailSvgPath$1(props, viewPort), fill: "currentColor" }))));
676
700
  };
677
701
  var CtaBubble = function (props) {
678
702
  var _a, _b, _c, _d;
@@ -685,10 +709,11 @@ var CtaBubble = function (props) {
685
709
  props.onDismiss();
686
710
  }
687
711
  };
712
+ console.log("Returning CTABubble with message: ", props.children);
688
713
  return (React$1.createElement("div", { ref: ref, style: {
689
- border: props.borderStyle ? 'solid' : 'none',
690
- borderWidth: ((_a = props.borderStyle) === null || _a === void 0 ? void 0 : _a.width) || '0px',
691
- borderColor: ((_b = props.borderStyle) === null || _b === void 0 ? void 0 : _b.color) || 'transparent',
714
+ border: props.borderStyle ? "solid" : "none",
715
+ borderWidth: ((_a = props.borderStyle) === null || _a === void 0 ? void 0 : _a.width) || "0px",
716
+ borderColor: ((_b = props.borderStyle) === null || _b === void 0 ? void 0 : _b.color) || "transparent",
692
717
  animation: "".concat(animation, " 1s infinite"),
693
718
  }, className: "cta-bubble", onClick: props.onClick },
694
719
  React$1.createElement(CtaBubbleTail, { width: (_c = rect === null || rect === void 0 ? void 0 : rect.width) !== null && _c !== void 0 ? _c : 0, height: (_d = rect === null || rect === void 0 ? void 0 : rect.height) !== null && _d !== void 0 ? _d : 0, direction: 60, angle: 45, length: 16 }),
@@ -700,54 +725,102 @@ var CtaBubble = function (props) {
700
725
 
701
726
  var CtaBubbleContainer = function (props) {
702
727
  var visible = props.visible, timeout = props.timeout, delay = props.delay, animate = props.animate, buttonAnimation = props.buttonAnimation, dismissible = props.dismissible, onClick = props.onClick, onDismiss = props.onDismiss, children = props.children;
728
+ // Debug: Log all props received
729
+ log("[CtaBubbleContainer] Props received:", {
730
+ visible: visible,
731
+ timeout: timeout,
732
+ delay: delay,
733
+ animate: animate,
734
+ buttonAnimation: buttonAnimation,
735
+ dismissible: dismissible,
736
+ hasOnClick: !!onClick,
737
+ hasOnDismiss: !!onDismiss,
738
+ hasChildren: !!children,
739
+ childrenContent: children,
740
+ });
703
741
  var startTime = useMemo(function () {
704
- return visible ? new Date().valueOf() : undefined;
742
+ var time = visible ? new Date().valueOf() : undefined;
743
+ log("[CtaBubbleContainer] StartTime calculated: visible=".concat(visible, ", startTime=").concat(time));
744
+ return time;
705
745
  }, [visible]);
706
746
  var _a = useState(false), showBubble = _a[0], setShowBubble = _a[1];
707
- var isMounted = useRef(true);
747
+ log("[CtaBubbleContainer] Current state: showBubble=".concat(showBubble));
708
748
  useEffect(function () {
749
+ log("[CtaBubbleContainer] useEffect triggered with:", {
750
+ startTime: startTime,
751
+ startTimeExists: !!startTime,
752
+ timeout: timeout,
753
+ timeoutType: typeof timeout,
754
+ delay: delay,
755
+ delayType: typeof delay,
756
+ visible: visible,
757
+ });
709
758
  var hideTimer = null;
759
+ var delayTimer = null;
760
+ var isMounted = true;
710
761
  if (startTime) {
711
- var delayTimer_1 = setTimeout(function () {
712
- if (isMounted.current) {
762
+ var actualDelay_1 = delay || 0;
763
+ log("[CtaBubbleContainer] Timer setup: actualDelay=".concat(actualDelay_1, "ms (from delay=").concat(delay, ")"));
764
+ delayTimer = setTimeout(function () {
765
+ log("[CtaBubbleContainer] Delay timer fired after ".concat(actualDelay_1, "ms, isMounted=").concat(isMounted));
766
+ if (isMounted) {
767
+ log("[CtaBubbleContainer] Component still mounted, setting showBubble=true");
713
768
  setShowBubble(true);
769
+ if (typeof timeout === "number") {
770
+ log("[CtaBubbleContainer] Hide timer setup: will hide after ".concat(timeout, "ms"));
771
+ hideTimer = setTimeout(function () {
772
+ log("[CtaBubbleContainer] Hide timer fired after ".concat(timeout, "ms, isMounted=").concat(isMounted));
773
+ if (isMounted) {
774
+ log("[CtaBubbleContainer] Component still mounted, setting showBubble=false");
775
+ setShowBubble(false);
776
+ }
777
+ else {
778
+ log("[CtaBubbleContainer] Component unmounted, skipping hide");
779
+ }
780
+ }, timeout);
781
+ }
782
+ else {
783
+ log("[CtaBubbleContainer] No hide timer set (timeout=".concat(timeout, ", type=").concat(typeof timeout, ")"));
784
+ }
714
785
  }
715
- if (typeof timeout === "number") {
716
- hideTimer = setTimeout(function () {
717
- if (isMounted.current) {
718
- setShowBubble(false);
719
- }
720
- }, timeout);
721
- }
722
- }, delay);
723
- return function () {
724
- if (hideTimer) {
725
- clearTimeout(hideTimer);
786
+ else {
787
+ log("[CtaBubbleContainer] Component unmounted before delay timer, not showing bubble");
726
788
  }
727
- clearTimeout(delayTimer_1);
728
- isMounted.current = false;
729
- };
789
+ }, actualDelay_1);
790
+ }
791
+ else {
792
+ log("[CtaBubbleContainer] No startTime, skipping timer setup");
730
793
  }
731
- // Return a cleanup function for the case where startTime is undefined
732
794
  return function () {
795
+ log("[CtaBubbleContainer] Cleanup triggered, unmounting component");
796
+ isMounted = false;
733
797
  if (hideTimer) {
798
+ log("[CtaBubbleContainer] Clearing hide timer");
734
799
  clearTimeout(hideTimer);
735
800
  }
736
- isMounted.current = false;
801
+ if (delayTimer) {
802
+ log("[CtaBubbleContainer] Clearing delay timer");
803
+ clearTimeout(delayTimer);
804
+ }
737
805
  };
738
- }, [startTime, timeout, delay]);
806
+ }, [startTime, timeout, delay, visible]);
739
807
  var handleDismiss = function () {
808
+ log("[CtaBubbleContainer] handleDismiss called, setting showBubble=false");
740
809
  setShowBubble(false);
741
810
  if (onDismiss) {
811
+ log("[CtaBubbleContainer] Calling onDismiss callback");
742
812
  onDismiss();
743
813
  }
744
814
  };
815
+ // Final render decision
816
+ var shouldRender = visible && showBubble;
817
+ log("[CtaBubbleContainer] Render decision: visible=".concat(visible, ", showBubble=").concat(showBubble, ", shouldRender=").concat(shouldRender));
745
818
  return (React$1.createElement(React$1.Fragment, null, visible && showBubble && (React$1.createElement(CtaBubble, { onClick: onClick, animate: animate, buttonAnimation: buttonAnimation, dismissible: dismissible, onDismiss: handleDismiss }, children))));
746
819
  };
747
820
 
748
821
  var ChatButton = function (_a) {
749
822
  var _b;
750
- var onClick = _a.onClick, addClass = _a.addClass, config = _a.config, visible = _a.visible, borderStyle = _a.borderStyle, imageUrl = _a.imageUrl;
823
+ var onClick = _a.onClick, addClass = _a.addClass, config = _a.config, visible = _a.visible, borderStyle = _a.borderStyle, imageUrl = _a.imageUrl, hasInteracted = _a.hasInteracted, onCtaDismiss = _a.onCtaDismiss;
751
824
  var _c = useState(defaultWidgetButtonWidth), buttonWidth = _c[0], setButtonWidth = _c[1];
752
825
  var _d = useState(false), animate = _d[0], setAnimate = _d[1];
753
826
  var mobileWidth = ((_b = config === null || config === void 0 ? void 0 : config.mobile) === null || _b === void 0 ? void 0 : _b.applyAtLessThanWidth) || defaultNonMobileScreenWidth;
@@ -766,6 +839,11 @@ var ChatButton = function (_a) {
766
839
  var _a;
767
840
  var delayTimer;
768
841
  var timeoutTimer;
842
+ // Don't animate if user has already interacted
843
+ if (hasInteracted) {
844
+ setAnimate(false);
845
+ return function () { }; // Return empty cleanup function
846
+ }
769
847
  // Use animationDelay if provided, otherwise fall back to delay for backwards compatibility
770
848
  var animationDelayToUse = (_a = configToApply === null || configToApply === void 0 ? void 0 : configToApply.animationDelay) !== null && _a !== void 0 ? _a : configToApply === null || configToApply === void 0 ? void 0 : configToApply.delay;
771
849
  if (animationDelayToUse) {
@@ -798,8 +876,8 @@ var ChatButton = function (_a) {
798
876
  if (timeoutTimer)
799
877
  clearTimeout(timeoutTimer);
800
878
  };
801
- }, [configToApply, setAnimate]);
802
- var animation = animate ? (configToApply === null || configToApply === void 0 ? void 0 : configToApply.animation) || "wiggle" : "none";
879
+ }, [configToApply, setAnimate, hasInteracted]);
880
+ var animation = animate && !hasInteracted ? (configToApply === null || configToApply === void 0 ? void 0 : configToApply.animation) || "wiggle" : "none";
803
881
  useEffect(function () {
804
882
  var handleResize = function () {
805
883
  var screenWidth = window.innerWidth;
@@ -831,8 +909,8 @@ var ChatButton = function (_a) {
831
909
  // Fallback to default SVG
832
910
  React$1.createElement("svg", { width: svgSize, height: svgSize, viewBox: "0 0 22 22" },
833
911
  React$1.createElement("path", { d: "M13 22l-4-6H2c-1.11-.043-2-.935-2-2V2C0 .89.89 0 2 0h18c1.11 0 2 .892 2 2v12c0 1.067-.89 1.957-2 2h-3l-4 6zm3-8h4c-.005.3-.01-12 0-12-.01.004-18 .006-18 0 .005.006 0 12 0 12h8l3 5 3-5z", fill: "#FFF", fillRule: "evenodd" })))),
834
- configToApply && configToApply.message && (React$1.createElement("div", { className: "xapp-chat-button__cta" },
835
- React$1.createElement(CtaBubbleContainer, { timeout: configToApply === null || configToApply === void 0 ? void 0 : configToApply.timeout, delay: configToApply === null || configToApply === void 0 ? void 0 : configToApply.delay, animate: animate, buttonAnimation: animation, dismissible: configToApply === null || configToApply === void 0 ? void 0 : configToApply.dismissible, visible: !visible /** Why is this !visible */ }, configToApply === null || configToApply === void 0 ? void 0 : configToApply.message)))));
912
+ configToApply && configToApply.message && !hasInteracted && (React$1.createElement("div", { className: "xapp-chat-button__cta" },
913
+ React$1.createElement(CtaBubbleContainer, { timeout: configToApply === null || configToApply === void 0 ? void 0 : configToApply.timeout, delay: configToApply === null || configToApply === void 0 ? void 0 : configToApply.delay, animate: animate, buttonAnimation: animation, dismissible: configToApply === null || configToApply === void 0 ? void 0 : configToApply.dismissible, visible: !visible /** Why is this !visible */, onDismiss: onCtaDismiss }, configToApply === null || configToApply === void 0 ? void 0 : configToApply.message)))));
836
914
  };
837
915
 
838
916
  var ChatCard = function (props) {
@@ -2812,6 +2890,7 @@ var StentorRouterChat = /** @class */ (function () {
2812
2890
  this._sessionId = "";
2813
2891
  this.accessToken = "";
2814
2892
  this.attributes = {};
2893
+ this.routerAttributes = {};
2815
2894
  this.isAdmin = false;
2816
2895
  this.urlAttributes = {};
2817
2896
  this.handlers = {};
@@ -2880,13 +2959,19 @@ var StentorRouterChat = /** @class */ (function () {
2880
2959
  this.handlers["new message"] = function (data, sender, ts) {
2881
2960
  // Because the router's internal message format is Stentor channel compatible.
2882
2961
  // So the data is either a stentor Request (from widget) or a stentor Response (from bot)
2883
- var _a;
2962
+ var _a, _b;
2884
2963
  var message;
2885
2964
  if (sender.deviceId === "Bot") {
2886
- if (typeof ((_a = _this.options.hooks) === null || _a === void 0 ? void 0 : _a.onResponse) === "function") {
2887
- _this.options.hooks.onResponse(message);
2965
+ var response = data;
2966
+ // Extract custom attributes from router response
2967
+ if (((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.routerAttributes) && typeof response.data.routerAttributes === "object") {
2968
+ _this.routerAttributes = __assign({}, response.data.routerAttributes);
2969
+ log("Extracted router attributes: ".concat(JSON.stringify(_this.routerAttributes)));
2970
+ }
2971
+ if (typeof ((_b = _this.options.hooks) === null || _b === void 0 ? void 0 : _b.onResponse) === "function") {
2972
+ _this.options.hooks.onResponse(response);
2888
2973
  }
2889
- message = responseToMessage(data);
2974
+ message = responseToMessage(response);
2890
2975
  }
2891
2976
  else if (sender.deviceId === "Widget") {
2892
2977
  message = requestToMessage(data);
@@ -3319,7 +3404,7 @@ var StentorRouterChat = /** @class */ (function () {
3319
3404
  };
3320
3405
  StentorRouterChat.prototype.postMessage = function (message) {
3321
3406
  return __awaiter$1(this, void 0, void 0, function () {
3322
- var userId, sessionId, accessToken, attributes, rwgToken, merchantId, environment, enablePreferredTime, service, origin, request;
3407
+ var userId, sessionId, accessToken, attributes, rwgToken, merchantId, environment, enablePreferredTime, service, origin, mergedAttributes, request;
3323
3408
  return __generator$1(this, function (_a) {
3324
3409
  userId = this._userId;
3325
3410
  sessionId = this._sessionId;
@@ -3349,7 +3434,8 @@ var StentorRouterChat = /** @class */ (function () {
3349
3434
  if (origin) {
3350
3435
  attributes["origin"] = origin;
3351
3436
  }
3352
- request = requestFromMessage(message, userId, this.isNewSession, sessionId, accessToken, attributes, this.visitorInfo);
3437
+ mergedAttributes = __assign(__assign({}, attributes), this.routerAttributes);
3438
+ request = requestFromMessage(message, userId, this.isNewSession, sessionId, accessToken, mergedAttributes, this.visitorInfo);
3353
3439
  this.emit("new message", request);
3354
3440
  return [2 /*return*/];
3355
3441
  });
@@ -7641,22 +7727,21 @@ var StentorServerChat = /** @class */ (function () {
7641
7727
  return StentorServerChat;
7642
7728
  }());
7643
7729
 
7644
- // import { useWhatChanged } from '@simbathesailor/use-what-changed';
7645
7730
  function createChatServerCore(config, options) {
7646
7731
  switch (config.type) {
7647
7732
  case "direct":
7648
7733
  return new StentorDirectChat({
7649
7734
  url: config.serverUrl,
7650
7735
  key: config.accountKey,
7651
- timeout: config.timeout
7736
+ timeout: config.timeout,
7652
7737
  }, options);
7653
7738
  case "websocket":
7654
7739
  return new StentorServerChat({
7655
- url: config.serverUrl
7740
+ url: config.serverUrl,
7656
7741
  }, options);
7657
7742
  case "websocketraw":
7658
7743
  return new StentorRouterChat({
7659
- url: config.serverUrl
7744
+ url: config.serverUrl,
7660
7745
  }, options);
7661
7746
  case "local":
7662
7747
  return new StentorLocalChat();
@@ -7675,6 +7760,11 @@ function useChatServer(config, options) {
7675
7760
  // Log what caused the "effect"
7676
7761
  // useWhatChanged(deps, "options, config, dispatch");
7677
7762
  useEffect(function () {
7763
+ // Don't create server if config is null (waiting for async config load)
7764
+ if (!config || !options) {
7765
+ setServer(undefined);
7766
+ return undefined;
7767
+ }
7678
7768
  var newServer = createChatServer(config, options);
7679
7769
  newServer.init(dispatch);
7680
7770
  setServer(newServer);
@@ -8959,13 +9049,25 @@ var SendIcon = function () {
8959
9049
  };
8960
9050
 
8961
9051
  var SendButton = function (props) {
8962
- return (React$1.createElement(React$1.Fragment, null, !props.sendButtonIcon ? (React$1.createElement(IconButton_1, { className: "xappw-send-button ".concat(props.className || ""), tabIndex: props.tabIndex, onClick: props.onClick, icon: SendIcon })) : (React$1.createElement("button", { className: "xappw-custom-send-button", tabIndex: props.tabIndex ? Number(props.tabIndex) : 0, onClick: props.onClick },
8963
- React$1.createElement("img", { src: props.sendButtonIcon, alt: "Send button", draggable: false })))));
9052
+ var _a = props.disabled, disabled = _a === void 0 ? false : _a;
9053
+ var _b = React$1.useState(false), isHovered = _b[0], setIsHovered = _b[1];
9054
+ // Determine which icon to show based on state
9055
+ var getIconSrc = function () {
9056
+ if (disabled && props.sendButtonIconDisabled) {
9057
+ return props.sendButtonIconDisabled;
9058
+ }
9059
+ if (isHovered && !disabled && props.sendButtonIconHover) {
9060
+ return props.sendButtonIconHover;
9061
+ }
9062
+ return props.sendButtonIcon;
9063
+ };
9064
+ return (React$1.createElement(React$1.Fragment, null, !props.sendButtonIcon ? (React$1.createElement(IconButton_1, { className: "xappw-send-button ".concat(props.className || "", " ").concat(disabled ? 'disabled' : ''), tabIndex: props.tabIndex, onClick: disabled ? undefined : props.onClick, icon: SendIcon })) : (React$1.createElement("button", { className: "xappw-custom-send-button ".concat(disabled ? 'disabled' : ''), tabIndex: props.tabIndex ? Number(props.tabIndex) : 0, onClick: props.onClick, disabled: disabled, onMouseEnter: function () { return setIsHovered(true); }, onMouseLeave: function () { return setIsHovered(false); } },
9065
+ React$1.createElement("img", { src: getIconSrc(), alt: "Send button", draggable: false, className: "send-button-icon" })))));
8964
9066
  };
8965
9067
 
8966
9068
  var Input = function (props) {
8967
9069
  var _a, _b;
8968
- var value = props.value, placeholder = props.placeholder, sendButtonIcon = props.sendButtonIcon, suggestion = props.suggestion, footerConfig = props.footerConfig, inputConfig = props.inputConfig, onChange = props.onChange, onSubmit = props.onSubmit, onSuggestionCommand = props.onSuggestionCommand;
9070
+ var value = props.value, placeholder = props.placeholder, sendButtonIcon = props.sendButtonIcon, sendButtonIconHover = props.sendButtonIconHover, sendButtonIconDisabled = props.sendButtonIconDisabled, suggestion = props.suggestion, footerConfig = props.footerConfig, inputConfig = props.inputConfig, onChange = props.onChange, onSubmit = props.onSubmit, onSuggestionCommand = props.onSuggestionCommand;
8969
9071
  var _c = useState(false), dragover = _c[0], setDragover = _c[1];
8970
9072
  function onDragOver(event) {
8971
9073
  setDragover(true);
@@ -9021,7 +9123,7 @@ var Input = function (props) {
9021
9123
  value: value, spellCheck: true }),
9022
9124
  React$1.createElement("div", { className: "xappw-input-form__buttons" },
9023
9125
  value.text && (React$1.createElement(IconButton_1, { icon: CloseIcon, tabIndex: (_a = footerConfig === null || footerConfig === void 0 ? void 0 : footerConfig.clearButton) === null || _a === void 0 ? void 0 : _a.tabIndex, className: "xappw-input-form__btn", onClick: handleClear })),
9024
- React$1.createElement(SendButton, { className: "xappw-input-form__btn", sendButtonIcon: sendButtonIcon, tabIndex: (_b = footerConfig === null || footerConfig === void 0 ? void 0 : footerConfig.sendButton) === null || _b === void 0 ? void 0 : _b.tabIndex, onClick: handleOnSubmit })))));
9126
+ React$1.createElement(SendButton, { className: "xappw-input-form__btn", sendButtonIcon: sendButtonIcon, sendButtonIconHover: sendButtonIconHover, sendButtonIconDisabled: sendButtonIconDisabled, tabIndex: (_b = footerConfig === null || footerConfig === void 0 ? void 0 : footerConfig.sendButton) === null || _b === void 0 ? void 0 : _b.tabIndex, disabled: !value.text, onClick: handleOnSubmit })))));
9025
9127
  };
9026
9128
 
9027
9129
  function createActions(onItemUse) {
@@ -9083,7 +9185,7 @@ var Suggestions = function (props) {
9083
9185
 
9084
9186
  var ChatFooter = function (props) {
9085
9187
  var _a, _b, _c;
9086
- var isAdmin = props.isAdmin, isChatting = props.isChatting, visible = props.visible, placeholder = props.placeholder, sendButtonIcon = props.sendButtonIcon, footerConfig = props.footerConfig, menuConfig = props.menuConfig, inputConfig = props.inputConfig, onSubmit = props.onSubmit;
9188
+ var isAdmin = props.isAdmin, isChatting = props.isChatting, visible = props.visible, placeholder = props.placeholder, sendButtonIcon = props.sendButtonIcon, sendButtonIconHover = props.sendButtonIconHover, sendButtonIconDisabled = props.sendButtonIconDisabled, footerConfig = props.footerConfig, menuConfig = props.menuConfig, inputConfig = props.inputConfig, onSubmit = props.onSubmit;
9087
9189
  var innerDispatch = useChatDispatch();
9088
9190
  var _d = useState(false), drawerOpen = _d[0], setDrawerState = _d[1]; // false initially
9089
9191
  var _e = useState(), suggestionSearch = _e[0], setSuggestionSearch = _e[1];
@@ -9149,7 +9251,7 @@ var ChatFooter = function (props) {
9149
9251
  React$1.createElement(Suggestions, { className: "xappw-chat-footer__suggestions", data: suggestions.suggestions, index: suggestions.index, searchTerms: suggestionSearch, onItemClick: handleItemClick, onItemUse: handleItemUse }),
9150
9252
  isAdmin && isChatting && visible && React$1.createElement(AdminBar, { onAdminJoin: handleAdminJoin }),
9151
9253
  React$1.createElement("div", { style: { pointerEvents: enableInput ? "auto" : "none", opacity: enableInput ? 1 : 0.5 } },
9152
- React$1.createElement(Input, { addClass: "chat-footer__input " + (isChatting && visible ? "visible" : ""), suggestion: suggestions.item, value: input, placeholder: placeholder, sendButtonIcon: sendButtonIcon, footerConfig: footerConfig, inputConfig: inputConfig, onSubmit: handleSubmit, onChange: handleChange, onSuggestionCommand: suggestions.execute,
9254
+ React$1.createElement(Input, { addClass: "chat-footer__input " + (isChatting && visible ? "visible" : ""), suggestion: suggestions.item, value: input, placeholder: placeholder, sendButtonIcon: sendButtonIcon, sendButtonIconHover: sendButtonIconHover, sendButtonIconDisabled: sendButtonIconDisabled, footerConfig: footerConfig, inputConfig: inputConfig, onSubmit: handleSubmit, onChange: handleChange, onSuggestionCommand: suggestions.execute,
9153
9255
  // onFocus={this.inputOnFocus}
9154
9256
  onFileUpload: props.onFileUpload })),
9155
9257
  brandingEnabled && brandingText && React$1.createElement(ChatBranding, { text: brandingText })));
@@ -31377,6 +31479,9 @@ function getButtonStyle(style) {
31377
31479
  _a.sent();
31378
31480
  return [4 /*yield*/, ["button-hover-bg", style === null || style === void 0 ? void 0 : style.hoverBackground]];
31379
31481
  case 4:
31482
+ _a.sent();
31483
+ return [4 /*yield*/, ["button-disabled-bg", style === null || style === void 0 ? void 0 : style.disabledBackground]];
31484
+ case 5:
31380
31485
  _a.sent();
31381
31486
  return [2 /*return*/];
31382
31487
  }
@@ -31433,6 +31538,270 @@ function getCtaStyle(style) {
31433
31538
  return union(getBackgroundStyle(style.background), getTextStyle(style.text));
31434
31539
  }
31435
31540
 
31541
+ /**
31542
+ * Safely stringify objects, handling circular references and errors
31543
+ */
31544
+ var safeStringify = function (arg) {
31545
+ if (arg === null)
31546
+ return "null";
31547
+ if (arg === undefined)
31548
+ return "undefined";
31549
+ if (typeof arg !== "object")
31550
+ return String(arg);
31551
+ try {
31552
+ var seen_1 = new WeakSet();
31553
+ return JSON.stringify(arg, function (_key, value) {
31554
+ if (typeof value === "object" && value !== null) {
31555
+ if (seen_1.has(value)) {
31556
+ return "[Circular]";
31557
+ }
31558
+ seen_1.add(value);
31559
+ }
31560
+ return value;
31561
+ }, 2);
31562
+ }
31563
+ catch (e) {
31564
+ return "[Object: ".concat(Object.prototype.toString.call(arg), "]");
31565
+ }
31566
+ };
31567
+ var ErrorOverlay = function (_a) {
31568
+ var enableErrorOverlay = _a.enableErrorOverlay;
31569
+ var _b = useState([]), errors = _b[0], setErrors = _b[1];
31570
+ var _c = useState(false), isMinimized = _c[0], setIsMinimized = _c[1];
31571
+ var _d = useState(true), isVisible = _d[0], setIsVisible = _d[1];
31572
+ var _e = useState(false), isEnabled = _e[0], setIsEnabled = _e[1];
31573
+ var _f = useState("bottom"), position = _f[0], setPosition = _f[1];
31574
+ // Check if error overlay should be enabled and load position
31575
+ useEffect(function () {
31576
+ var _a;
31577
+ var checkEnabled = function () {
31578
+ var _a;
31579
+ if (typeof window === "undefined")
31580
+ return false;
31581
+ // 1. Check localStorage (highest priority)
31582
+ var localStorageSetting = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem("xaErrorOverlay");
31583
+ if (localStorageSetting === "enabled") {
31584
+ console.log("[ErrorOverlay] Enabled via localStorage");
31585
+ return true;
31586
+ }
31587
+ if (localStorageSetting === "disabled") {
31588
+ console.log("[ErrorOverlay] Disabled via localStorage");
31589
+ return false;
31590
+ }
31591
+ // 2. Check widget configuration
31592
+ if (enableErrorOverlay !== undefined) {
31593
+ console.log("[ErrorOverlay] Using config setting:", enableErrorOverlay);
31594
+ return enableErrorOverlay;
31595
+ }
31596
+ // 3. Check for React Native dev mode
31597
+ if (typeof globalThis.__DEV__ !== "undefined" && globalThis.__DEV__) {
31598
+ console.log("[ErrorOverlay] Enabled via __DEV__");
31599
+ return true;
31600
+ }
31601
+ // 4. Default: disabled
31602
+ return false;
31603
+ };
31604
+ var enabled = checkEnabled();
31605
+ setIsEnabled(enabled);
31606
+ // Load position preference
31607
+ var savedPosition = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem("xaErrorOverlayPosition");
31608
+ if (savedPosition === "top" || savedPosition === "bottom") {
31609
+ setPosition(savedPosition);
31610
+ }
31611
+ console.log("[ErrorOverlay] Component mounted, enabled:", enabled, "position:", savedPosition || "bottom");
31612
+ }, [enableErrorOverlay]);
31613
+ // Define addError with useCallback to prevent stale closures
31614
+ var addError = useCallback(function (error) {
31615
+ console.log("[ErrorOverlay] Adding error:", error);
31616
+ setErrors(function (prev) {
31617
+ var timestamp = new Date().toISOString();
31618
+ // Check if this is a duplicate of the last error
31619
+ var lastError = prev[prev.length - 1];
31620
+ if (lastError && lastError.message === error.message) {
31621
+ // Update count of last error
31622
+ return __spreadArray$1(__spreadArray$1([], prev.slice(0, -1), true), [
31623
+ __assign(__assign({}, lastError), { count: lastError.count + 1, timestamp: timestamp }),
31624
+ ], false);
31625
+ }
31626
+ // Add new error
31627
+ var newError = __assign({ id: "".concat(timestamp, "-").concat(Math.random()), timestamp: timestamp, count: 1 }, error);
31628
+ // Keep only last 50 errors
31629
+ var updated = __spreadArray$1(__spreadArray$1([], prev, true), [newError], false);
31630
+ return updated.slice(-50);
31631
+ });
31632
+ }, []);
31633
+ useEffect(function () {
31634
+ if (!isEnabled) {
31635
+ console.log("[ErrorOverlay] Not enabled, skipping error interception");
31636
+ return undefined;
31637
+ }
31638
+ console.log("[ErrorOverlay] Setting up error interception");
31639
+ // Store original console methods
31640
+ var originalError = console.error;
31641
+ var originalWarn = console.warn;
31642
+ // Override console.error
31643
+ console.error = function () {
31644
+ var args = [];
31645
+ for (var _i = 0; _i < arguments.length; _i++) {
31646
+ args[_i] = arguments[_i];
31647
+ }
31648
+ var message = args.map(function (arg) { return safeStringify(arg); }).join(" ");
31649
+ var error = new Error();
31650
+ addError({
31651
+ message: message,
31652
+ type: "error",
31653
+ stack: error.stack,
31654
+ });
31655
+ // Call original method
31656
+ originalError.apply(console, args);
31657
+ };
31658
+ // Override console.warn
31659
+ console.warn = function () {
31660
+ var args = [];
31661
+ for (var _i = 0; _i < arguments.length; _i++) {
31662
+ args[_i] = arguments[_i];
31663
+ }
31664
+ var message = args.map(function (arg) { return safeStringify(arg); }).join(" ");
31665
+ addError({
31666
+ message: message,
31667
+ type: "warning",
31668
+ });
31669
+ // Call original method
31670
+ originalWarn.apply(console, args);
31671
+ };
31672
+ // Capture unhandled errors
31673
+ var handleError = function (event) {
31674
+ var _a;
31675
+ addError({
31676
+ message: event.message,
31677
+ type: "error",
31678
+ stack: (_a = event.error) === null || _a === void 0 ? void 0 : _a.stack,
31679
+ });
31680
+ };
31681
+ // Capture unhandled promise rejections
31682
+ var handleRejection = function (event) {
31683
+ var _a;
31684
+ addError({
31685
+ message: "Unhandled Promise Rejection: ".concat(event.reason),
31686
+ type: "error",
31687
+ stack: (_a = event.reason) === null || _a === void 0 ? void 0 : _a.stack,
31688
+ });
31689
+ };
31690
+ window.addEventListener("error", handleError);
31691
+ window.addEventListener("unhandledrejection", handleRejection);
31692
+ // Cleanup
31693
+ return function () {
31694
+ console.log("[ErrorOverlay] Cleaning up error interception");
31695
+ console.error = originalError;
31696
+ console.warn = originalWarn;
31697
+ window.removeEventListener("error", handleError);
31698
+ window.removeEventListener("unhandledrejection", handleRejection);
31699
+ };
31700
+ }, [isEnabled, addError]);
31701
+ var clearErrors = function () {
31702
+ setErrors([]);
31703
+ };
31704
+ var copyToClipboard = function () { return __awaiter$1(void 0, void 0, void 0, function () {
31705
+ var errorText, err_1, textarea;
31706
+ return __generator$1(this, function (_a) {
31707
+ switch (_a.label) {
31708
+ case 0:
31709
+ errorText = errors
31710
+ .map(function (e) {
31711
+ return "[".concat(e.timestamp, "] ").concat(e.type.toUpperCase(), ": ").concat(e.message).concat(e.stack ? "\n" + e.stack : "");
31712
+ })
31713
+ .join("\n\n");
31714
+ _a.label = 1;
31715
+ case 1:
31716
+ _a.trys.push([1, 3, , 4]);
31717
+ return [4 /*yield*/, navigator.clipboard.writeText(errorText)];
31718
+ case 2:
31719
+ _a.sent();
31720
+ console.log("[ErrorOverlay] Errors copied to clipboard");
31721
+ return [3 /*break*/, 4];
31722
+ case 3:
31723
+ err_1 = _a.sent();
31724
+ console.error("[ErrorOverlay] Failed to copy to clipboard:", err_1);
31725
+ textarea = document.createElement("textarea");
31726
+ textarea.value = errorText;
31727
+ textarea.style.position = "fixed";
31728
+ textarea.style.opacity = "0";
31729
+ document.body.appendChild(textarea);
31730
+ textarea.select();
31731
+ try {
31732
+ document.execCommand("copy");
31733
+ console.log("[ErrorOverlay] Errors copied to clipboard using fallback method");
31734
+ }
31735
+ catch (fallbackErr) {
31736
+ console.error("[ErrorOverlay] Fallback copy method also failed:", fallbackErr);
31737
+ }
31738
+ document.body.removeChild(textarea);
31739
+ return [3 /*break*/, 4];
31740
+ case 4: return [2 /*return*/];
31741
+ }
31742
+ });
31743
+ }); };
31744
+ // Toggle enabled state
31745
+ var toggleEnabled = function () {
31746
+ var newState = !isEnabled;
31747
+ setIsEnabled(newState);
31748
+ if (typeof window !== "undefined" && window.localStorage) {
31749
+ window.localStorage.setItem("xaErrorOverlay", newState ? "enabled" : "disabled");
31750
+ }
31751
+ console.log("[ErrorOverlay] Toggled enabled state to:", newState);
31752
+ // Clear errors when disabling
31753
+ if (!newState) {
31754
+ setErrors([]);
31755
+ }
31756
+ };
31757
+ // Toggle position between top and bottom
31758
+ var togglePosition = function () {
31759
+ var newPosition = position === "bottom" ? "top" : "bottom";
31760
+ setPosition(newPosition);
31761
+ if (typeof window !== "undefined" && window.localStorage) {
31762
+ window.localStorage.setItem("xaErrorOverlayPosition", newPosition);
31763
+ }
31764
+ };
31765
+ // Don't render anything if not enabled
31766
+ if (!isEnabled) {
31767
+ return null;
31768
+ }
31769
+ // If enabled but not visible (user closed it), don't render
31770
+ if (!isVisible) {
31771
+ return null;
31772
+ }
31773
+ // If enabled and visible but no errors yet, don't show the overlay
31774
+ // Only show when there are actual errors to display
31775
+ if (errors.length === 0) {
31776
+ return null;
31777
+ }
31778
+ return (React$1.createElement("div", { className: "error-overlay error-overlay--".concat(position, " ").concat(isMinimized ? "minimized" : "") },
31779
+ React$1.createElement("div", { className: "error-overlay-header" },
31780
+ React$1.createElement("span", { className: "error-overlay-title" },
31781
+ "Debug Console (",
31782
+ errors.length,
31783
+ ")"),
31784
+ React$1.createElement("div", { className: "error-overlay-actions" },
31785
+ React$1.createElement("button", { onClick: copyToClipboard, title: "Copy all to clipboard" }, "\uD83D\uDCCB"),
31786
+ React$1.createElement("button", { onClick: clearErrors, title: "Clear all" }, "\uD83D\uDDD1\uFE0F"),
31787
+ React$1.createElement("button", { onClick: togglePosition, title: "Move to ".concat(position === "bottom" ? "top" : "bottom") }, position === "bottom" ? "⬆️" : "⬇️"),
31788
+ React$1.createElement("button", { onClick: toggleEnabled, title: "Disable Error Overlay" }, "\uD83D\uDD27"),
31789
+ React$1.createElement("button", { onClick: function () { return setIsMinimized(!isMinimized); }, title: "Minimize/Maximize" }, isMinimized ? "▲" : "▼"),
31790
+ React$1.createElement("button", { onClick: function () { return setIsVisible(false); }, title: "Close" }, "\u2715"))),
31791
+ !isMinimized && (React$1.createElement("div", { className: "error-overlay-content" }, errors.map(function (error) { return (React$1.createElement("div", { key: error.id, className: "error-entry error-".concat(error.type) },
31792
+ React$1.createElement("div", { className: "error-header" },
31793
+ React$1.createElement("span", { className: "error-time" }, new Date(error.timestamp).toLocaleTimeString()),
31794
+ error.count > 1 && (React$1.createElement("span", { className: "error-count" },
31795
+ "(",
31796
+ error.count,
31797
+ "x)")),
31798
+ React$1.createElement("span", { className: "error-badge error-badge-".concat(error.type) }, error.type)),
31799
+ React$1.createElement("div", { className: "error-message" }, error.message),
31800
+ error.stack && (React$1.createElement("details", { className: "error-stack" },
31801
+ React$1.createElement("summary", null, "Stack trace"),
31802
+ React$1.createElement("pre", null, error.stack))))); })))));
31803
+ };
31804
+
31436
31805
  var ModalContent = function (_a) {
31437
31806
  var onClose = _a.onClose, onReset = _a.onReset;
31438
31807
  return (React$1.createElement("div", { className: "modalContent" },
@@ -31445,7 +31814,44 @@ var ModalContent = function (_a) {
31445
31814
  };
31446
31815
 
31447
31816
  var ChatWidgetWrapper = function (props) {
31448
- var rawConfig = props.config;
31817
+ var _a;
31818
+ var _b = useState(props.config), rawConfig = _b[0], setRawConfig = _b[1];
31819
+ var _c = useState(!!props.getConfig), configLoading = _c[0], setConfigLoading = _c[1];
31820
+ var _d = useState(), configError = _d[0], setConfigError = _d[1];
31821
+ // Load config from callback if provided
31822
+ useEffect(function () {
31823
+ var cancelled = false;
31824
+ if (props.getConfig) {
31825
+ setConfigLoading(true);
31826
+ setConfigError(undefined);
31827
+ props
31828
+ .getConfig()
31829
+ .then(function (config) {
31830
+ if (!cancelled) {
31831
+ setRawConfig(config);
31832
+ setConfigLoading(false);
31833
+ log("[ChatWidget] Config loaded from getConfig callback");
31834
+ }
31835
+ })
31836
+ .catch(function (error) {
31837
+ if (!cancelled) {
31838
+ setConfigError(error);
31839
+ setConfigLoading(false);
31840
+ err("[ChatWidget] Failed to load config: ".concat(error.message));
31841
+ }
31842
+ });
31843
+ }
31844
+ else if (props.config) {
31845
+ // If no callback, use the config prop directly
31846
+ setRawConfig(props.config);
31847
+ setConfigLoading(false);
31848
+ }
31849
+ return function () {
31850
+ cancelled = true;
31851
+ };
31852
+ // Only depend on getConfig and config - not the entire props object to avoid infinite loops
31853
+ // eslint-disable-next-line react-hooks/exhaustive-deps
31854
+ }, [props.getConfig, props.config]);
31449
31855
  var connection = useConnectionInfo(rawConfig);
31450
31856
  var config = useMemo(function () {
31451
31857
  var _a;
@@ -31454,7 +31860,7 @@ var ChatWidgetWrapper = function (props) {
31454
31860
  var token = useSelector(function (state) { return state.connection.token; });
31455
31861
  var options = useMemo(function () {
31456
31862
  var configurableMessages = getConfigurableMessages();
31457
- if (rawConfig.configurableMessages &&
31863
+ if ((rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.configurableMessages) &&
31458
31864
  Array.isArray(rawConfig.configurableMessages.items) &&
31459
31865
  rawConfig.configurableMessages.items.length > 0) {
31460
31866
  configurableMessages = rawConfig.configurableMessages;
@@ -31463,20 +31869,37 @@ var ChatWidgetWrapper = function (props) {
31463
31869
  token: token,
31464
31870
  bot: {
31465
31871
  nick: "Bot",
31466
- displayName: rawConfig.botName,
31467
- avatarPath: rawConfig.avatarUrl
31872
+ displayName: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.botName,
31873
+ avatarPath: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.avatarUrl,
31468
31874
  },
31469
31875
  configurableMessages: configurableMessages,
31470
- hooks: rawConfig.hooks
31876
+ hooks: rawConfig === null || rawConfig === void 0 ? void 0 : rawConfig.hooks,
31471
31877
  };
31472
31878
  }, [token, rawConfig]);
31473
- var chatServer = useChatServer(connection, options);
31879
+ // Only create chat server when config is ready (not loading and no error)
31880
+ var chatServer = useChatServer(configLoading || configError ? null : connection, configLoading || configError ? null : options);
31881
+ // Determine mode class for loading/error states
31882
+ var mode = (_a = props.mode) !== null && _a !== void 0 ? _a : "normal";
31883
+ var modeClass = "widget-container--".concat(mode);
31884
+ // Show loading state while config is being fetched
31885
+ if (configLoading) {
31886
+ return (React$1.createElement("div", { className: "widget-container widget-container--loading ".concat(modeClass) },
31887
+ React$1.createElement("div", { className: "xa-spinner-container visible" },
31888
+ React$1.createElement("div", { className: "xa-spinner" }))));
31889
+ }
31890
+ // Show error state if config failed to load
31891
+ if (configError) {
31892
+ return (React$1.createElement("div", { className: "widget-container widget-container--error ".concat(modeClass) },
31893
+ React$1.createElement("div", { className: "widget-error-message" },
31894
+ "Failed to load chat configuration: ",
31895
+ configError.message)));
31896
+ }
31474
31897
  return (React$1.createElement(ChatConfigContext.Provider, { value: config },
31475
31898
  React$1.createElement(ChatServerContext.Provider, { value: chatServer },
31476
- React$1.createElement(ChatWidget, __assign({}, props)))));
31899
+ React$1.createElement(ChatWidget, __assign({}, props, { config: rawConfig })))));
31477
31900
  };
31478
31901
  var ChatWidget = function (props) {
31479
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
31902
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7;
31480
31903
  var innerDispatch = useChatDispatch();
31481
31904
  var dispatch = useChatServerDispatch();
31482
31905
  // From Redux
@@ -31490,7 +31913,7 @@ var ChatWidget = function (props) {
31490
31913
  var canRefresh = (_c = (_b = props.config.header) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.refresh;
31491
31914
  // can't minimize in docked mode or static mode.
31492
31915
  var canMinimize = !dockedMode && !staticMode && ((_e = (_d = props.config.header) === null || _d === void 0 ? void 0 : _d.actions) === null || _e === void 0 ? void 0 : _e.minimize);
31493
- log("docked: ".concat(dockedMode, " static: ").concat(staticMode, " minimimized: ").concat((_g = (_f = props.config.header) === null || _f === void 0 ? void 0 : _f.actions) === null || _g === void 0 ? void 0 : _g.minimize));
31916
+ log("docked: ".concat(dockedMode, " static: ").concat(staticMode, " minimized: ").concat((_g = (_f = props.config.header) === null || _f === void 0 ? void 0 : _f.actions) === null || _g === void 0 ? void 0 : _g.minimize));
31494
31917
  var canCancel;
31495
31918
  // To preserve legacy behavior, cancel needs a little more checks
31496
31919
  if (typeof ((_j = (_h = props.config.header) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.cancel) === "boolean") {
@@ -31499,17 +31922,17 @@ var ChatWidget = function (props) {
31499
31922
  else {
31500
31923
  canCancel = !dockedMode && !staticMode;
31501
31924
  }
31502
- // For backward compatibility. Note: the action will create the actual "visuals" object" (this is a copy).
31925
+ // For backward compatibility. Note: the action will create the actual "visuals" object" (this is a copy).
31503
31926
  if (!chatState.visuals) {
31504
31927
  chatState.visuals = {};
31505
31928
  }
31506
31929
  // Our state - pull from storage
31507
- var _3 = useState((!canMinimize && !canCancel) ||
31930
+ var _8 = useState((!canMinimize && !canCancel) ||
31508
31931
  // !!get("visible") ||
31509
31932
  chatState.visuals.visible ||
31510
31933
  (((_m = props.config) === null || _m === void 0 ? void 0 : _m.autoOpenOnWidth) &&
31511
- window.matchMedia("(min-width: ".concat((_o = props.config) === null || _o === void 0 ? void 0 : _o.autoOpenOnWidth, ")")).matches)), visible = _3[0], setVisibleState = _3[1];
31512
- var _4 = useState(false), typing = _4[0], setTypingState = _4[1]; // false initially
31934
+ window.matchMedia("(min-width: ".concat((_o = props.config) === null || _o === void 0 ? void 0 : _o.autoOpenOnWidth, ")")).matches)), visible = _8[0], setVisibleState = _8[1];
31935
+ var _9 = useState(false), typing = _9[0], setTypingState = _9[1]; // false initially
31513
31936
  var chatServer = useContext(ChatServerContext);
31514
31937
  var patternsConfig = (_q = (_p = props.config) === null || _p === void 0 ? void 0 : _p.autoOpenOnPattern) === null || _q === void 0 ? void 0 : _q.patterns;
31515
31938
  var currentUrl = window.location.href;
@@ -31524,32 +31947,36 @@ var ChatWidget = function (props) {
31524
31947
  }
31525
31948
  setVisibleState(newVisible);
31526
31949
  innerDispatch(setVisualStatus({
31527
- visible: newVisible
31950
+ visible: newVisible,
31528
31951
  }));
31529
31952
  }, [innerDispatch, staticMode]);
31530
31953
  useEffect(function () {
31531
31954
  var _a, _b;
31532
- document.addEventListener("keydown", function (event) {
31955
+ var handleKeyDown = function (event) {
31533
31956
  var body = document.getElementsByTagName("body")[0];
31534
31957
  body.tabIndex = -1;
31535
31958
  if (event.key === "Escape") {
31536
31959
  body.focus();
31537
31960
  }
31538
- });
31961
+ };
31962
+ document.addEventListener("keydown", handleKeyDown);
31539
31963
  if (checkSessionExpiration((chatState === null || chatState === void 0 ? void 0 : chatState.sessionExpiration) || ((_a = props.config) === null || _a === void 0 ? void 0 : _a.sessionExpiration), (_b = chatState === null || chatState === void 0 ? void 0 : chatState.chats[chatState.chats.length - 1]) === null || _b === void 0 ? void 0 : _b.timestamp, chatState === null || chatState === void 0 ? void 0 : chatState.lastTimestamp)) {
31540
31964
  innerDispatch(setSessionId(undefined));
31541
31965
  innerDispatch(reset());
31542
31966
  }
31967
+ return function () {
31968
+ document.removeEventListener("keydown", handleKeyDown);
31969
+ };
31543
31970
  // eslint-disable-next-line react-hooks/exhaustive-deps
31544
31971
  }, []);
31545
- var _5 = useState(!document.hidden), isTabVisible = _5[0], setIsTabVisible = _5[1];
31972
+ var _10 = useState(!document.hidden), isTabVisible = _10[0], setIsTabVisible = _10[1];
31546
31973
  useEffect(function () {
31547
31974
  var handleVisibilityChange = function () {
31548
31975
  setIsTabVisible(!document.hidden);
31549
31976
  };
31550
- document.addEventListener('visibilitychange', handleVisibilityChange);
31977
+ document.addEventListener("visibilitychange", handleVisibilityChange);
31551
31978
  return function () {
31552
- document.removeEventListener('visibilitychange', handleVisibilityChange);
31979
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
31553
31980
  };
31554
31981
  }, []);
31555
31982
  useEffect(function () {
@@ -31583,7 +32010,15 @@ var ChatWidget = function (props) {
31583
32010
  if (currentWidth < +configWidth) {
31584
32011
  setVisible(false);
31585
32012
  }
31586
- }, [currentWidth, patternExist, patternMatches, configWidth, setVisible, chatState.visuals.opened, mode]);
32013
+ }, [
32014
+ currentWidth,
32015
+ patternExist,
32016
+ patternMatches,
32017
+ configWidth,
32018
+ setVisible,
32019
+ chatState.visuals.opened,
32020
+ mode,
32021
+ ]);
31587
32022
  function handleOnChange() {
31588
32023
  if (!typing) {
31589
32024
  dispatch(sendTyping(true));
@@ -31655,28 +32090,37 @@ var ChatWidget = function (props) {
31655
32090
  /** Called when minimize button is clicked */
31656
32091
  function handleMinimizeClick() {
31657
32092
  innerDispatch(setVisualStatus({
31658
- opened: false
32093
+ opened: false,
32094
+ hasInteracted: true,
31659
32095
  }));
31660
32096
  setVisible(false);
31661
32097
  }
31662
32098
  /** Called when cancel is clicked */
31663
32099
  function handleCancelClick() {
31664
- //set("opened", false);
32100
+ // First reset to clear all state
32101
+ innerDispatch(reset());
32102
+ // Then set hasInteracted to prevent CTA from showing after cancel
31665
32103
  innerDispatch(setVisualStatus({
31666
- opened: false
32104
+ opened: false,
32105
+ hasInteracted: true,
31667
32106
  }));
31668
- innerDispatch(reset());
31669
32107
  setVisible(false);
31670
32108
  }
31671
32109
  function chatButtonOnClick() {
31672
32110
  innerDispatch(setVisualStatus({
31673
- opened: true
32111
+ opened: true,
32112
+ hasInteracted: true,
31674
32113
  }));
31675
32114
  setVisible(true);
31676
32115
  setTimeout(function () {
31677
32116
  document.getElementById("chatWidgetInput").focus();
31678
32117
  }, 100);
31679
32118
  }
32119
+ function handleCtaDismiss() {
32120
+ innerDispatch(setVisualStatus({
32121
+ hasInteracted: true,
32122
+ }));
32123
+ }
31680
32124
  var isOffline = chatState.accountStatus === "offline" && !chatState.isChatting;
31681
32125
  var messages = chatState && chatState.chats;
31682
32126
  var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
@@ -31689,8 +32133,12 @@ var ChatWidget = function (props) {
31689
32133
  }, [connectionStatus, onConnectionStatusChange]);
31690
32134
  useExternalScript((_t = props.config) === null || _t === void 0 ? void 0 : _t.middlewareUrl);
31691
32135
  // This is a pseudo agent. It represent's the widget (shown in the header avatar for instance)
31692
- var widgetAgent = ((_u = chatState.agents["agent:robot"]) === null || _u === void 0 ? void 0 : _u.user) || (config === null || config === void 0 ? void 0 : config.agent)
31693
- || { nick: "agent:robot", avatarPath: config.avatarUrl, display_name: "Agent" };
32136
+ var widgetAgent = ((_u = chatState.agents["agent:robot"]) === null || _u === void 0 ? void 0 : _u.user) ||
32137
+ (config === null || config === void 0 ? void 0 : config.agent) || {
32138
+ nick: "agent:robot",
32139
+ avatarPath: config.avatarUrl,
32140
+ display_name: "Agent",
32141
+ };
31694
32142
  return (React$1.createElement(React$1.Fragment, null,
31695
32143
  React$1.createElement("div", { className: "widget-container ".concat(modeClass, " ").concat(getVisibilityClass()) },
31696
32144
  React$1.createElement(WidgetStylesheet, { theme: config === null || config === void 0 ? void 0 : config.theme }),
@@ -31699,10 +32147,11 @@ var ChatWidget = function (props) {
31699
32147
  React$1.createElement("div", { className: "xa-spinner-container ".concat(visible && connectionStatus === "pending" ? "visible" : "") },
31700
32148
  React$1.createElement("div", { className: "xa-spinner" })),
31701
32149
  connectionStatus === "offline" && React$1.createElement(ServerOffline, null),
31702
- React$1.createElement(ChatFooter, { isAdmin: config === null || config === void 0 ? void 0 : config.isAdmin, isChatting: chatState.isChatting, placeholder: (_x = config === null || config === void 0 ? void 0 : config.input) === null || _x === void 0 ? void 0 : _x.placeholder, sendButtonIcon: (_z = (_y = config === null || config === void 0 ? void 0 : config.footer) === null || _y === void 0 ? void 0 : _y.sendButton) === null || _z === void 0 ? void 0 : _z.icon, visible: visible, menuConfig: props.config.menu, footerConfig: (_0 = props.config) === null || _0 === void 0 ? void 0 : _0.footer, inputConfig: (_1 = props.config) === null || _1 === void 0 ? void 0 : _1.input, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }),
32150
+ React$1.createElement(ChatFooter, { isAdmin: config === null || config === void 0 ? void 0 : config.isAdmin, isChatting: chatState.isChatting, placeholder: (_x = config === null || config === void 0 ? void 0 : config.input) === null || _x === void 0 ? void 0 : _x.placeholder, sendButtonIcon: (_z = (_y = config === null || config === void 0 ? void 0 : config.footer) === null || _y === void 0 ? void 0 : _y.sendButton) === null || _z === void 0 ? void 0 : _z.icon, sendButtonIconHover: (_1 = (_0 = config === null || config === void 0 ? void 0 : config.footer) === null || _0 === void 0 ? void 0 : _0.sendButton) === null || _1 === void 0 ? void 0 : _1.iconHover, sendButtonIconDisabled: (_3 = (_2 = config === null || config === void 0 ? void 0 : config.footer) === null || _2 === void 0 ? void 0 : _2.sendButton) === null || _3 === void 0 ? void 0 : _3.iconDisabled, visible: visible, menuConfig: props.config.menu, footerConfig: (_4 = props.config) === null || _4 === void 0 ? void 0 : _4.footer, inputConfig: (_5 = props.config) === null || _5 === void 0 ? void 0 : _5.input, onChange: handleOnChange, onSubmit: handleOnSubmit, onFileUpload: handleFileUpload }),
31703
32151
  React$1.createElement("div", { className: "restartModal", ref: modalRef, onClick: handleRestartModalCloseClick },
31704
32152
  React$1.createElement(ModalContent, { onClose: handleRestartModalCloseClick, onReset: handleReset }))),
31705
- React$1.createElement(ChatButton, { addClass: getVisibilityClass(), onClick: chatButtonOnClick, config: config === null || config === void 0 ? void 0 : config.cta, imageUrl: (_2 = config === null || config === void 0 ? void 0 : config.chatButton) === null || _2 === void 0 ? void 0 : _2.imageUrl, visible: visible })));
32153
+ React$1.createElement(ChatButton, { addClass: getVisibilityClass(), onClick: chatButtonOnClick, config: config === null || config === void 0 ? void 0 : config.cta, imageUrl: (_6 = config === null || config === void 0 ? void 0 : config.chatButton) === null || _6 === void 0 ? void 0 : _6.imageUrl, visible: visible, hasInteracted: (_7 = chatState.visuals) === null || _7 === void 0 ? void 0 : _7.hasInteracted, onCtaDismiss: handleCtaDismiss }),
32154
+ React$1.createElement(ErrorOverlay, { enableErrorOverlay: config === null || config === void 0 ? void 0 : config.enableErrorOverlay })));
31706
32155
  };
31707
32156
 
31708
32157
  // src/utils/formatProdErrorMessage.ts
@@ -32179,17 +32628,37 @@ var DEFAULT_VISITOR = {
32179
32628
  nick: "visitor:",
32180
32629
  typing: false
32181
32630
  };
32182
- function createDefaultState(state) {
32631
+ function createDefaultState(state, options) {
32632
+ var _a;
32183
32633
  if (!state) {
32184
32634
  state = {};
32185
32635
  }
32186
32636
  state.userId = state.userId ? state.userId : visitorFingerprint();
32187
32637
  state.visitorId = state.userId;
32638
+ // Determine if debug mode should be enabled
32639
+ var debugMode = false;
32640
+ if (typeof window !== 'undefined') {
32641
+ var localStorageSetting = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.getItem('xaErrorOverlay');
32642
+ if (localStorageSetting === 'enabled') {
32643
+ debugMode = true;
32644
+ }
32645
+ else if (localStorageSetting === 'disabled') {
32646
+ debugMode = false;
32647
+ }
32648
+ else if (options === null || options === void 0 ? void 0 : options.enableErrorOverlay) {
32649
+ // Use config option if no localStorage override
32650
+ debugMode = true;
32651
+ }
32652
+ else if (typeof globalThis.__DEV__ !== 'undefined' && globalThis.__DEV__) {
32653
+ // For React Native, default to true in development mode
32654
+ debugMode = true;
32655
+ }
32656
+ }
32188
32657
  return __assign({ connection: {
32189
32658
  connectionStatus: "offline",
32190
32659
  token: null,
32191
32660
  greetingRequested: false
32192
- }, accountStatus: "offline", departments: {}, visitor: DEFAULT_VISITOR, agents: {}, chats: [], lastTimestamp: 0, lastRatingRequestTimestamp: 0, hasRating: false, isChatting: false, queuePosition: 0, failureMsg: null, visitorId: visitorFingerprint(), chips: [], sessionExpiration: "24h", visuals: {} }, state);
32661
+ }, accountStatus: "offline", departments: {}, visitor: DEFAULT_VISITOR, agents: {}, chats: [], lastTimestamp: 0, lastRatingRequestTimestamp: 0, hasRating: false, isChatting: false, queuePosition: 0, failureMsg: null, visitorId: visitorFingerprint(), chips: [], sessionExpiration: "24h", visuals: {}, debugMode: debugMode }, state);
32193
32662
  }
32194
32663
  var DEFAULT_STATE = createDefaultState();
32195
32664
 
@@ -32238,6 +32707,10 @@ var LocalStorage = /** @class */ (function () {
32238
32707
  function persistStateReducer(storage, initialState, innerReducer) {
32239
32708
  var _a;
32240
32709
  var obj = (_a = storage.get()) !== null && _a !== void 0 ? _a : initialState;
32710
+ // Clean up hasInteracted flag on page load - don't persist across browser refreshes
32711
+ if (obj && obj.visuals) {
32712
+ obj = __assign(__assign({}, obj), { visuals: __assign(__assign({}, obj.visuals), { hasInteracted: undefined }) });
32713
+ }
32241
32714
  return function (state, action) {
32242
32715
  if (state === void 0) { state = obj; }
32243
32716
  var res = innerReducer(state, action);
@@ -32296,13 +32769,14 @@ function memberLeave(state, detail) {
32296
32769
 
32297
32770
  function resetReducer(state) {
32298
32771
  if (state === void 0) { state = DEFAULT_STATE; }
32299
- // pass through some of the items to persis
32300
32772
  return __assign(__assign({}, createDefaultState({
32301
32773
  accessToken: state.accessToken,
32302
32774
  userId: state.userId,
32303
32775
  attributes: state.attributes,
32304
32776
  sessionExpiration: state.sessionExpiration
32305
- })), { connection: __assign(__assign({}, state.connection), { greetingRequested: false, nonce: uuid_1() }), visitor: state.visitor, visitorId: state.visitorId });
32777
+ })), { connection: __assign(__assign({}, state.connection), { greetingRequested: false, nonce: uuid_1() }), visitor: state.visitor, visitorId: state.visitorId,
32778
+ // Explicitly reset visuals to clear hasInteracted flag for widget refresh
32779
+ visuals: {} });
32306
32780
  }
32307
32781
 
32308
32782
  // todo: create reducer (requires redux-thunk dependency)
@@ -32335,7 +32809,14 @@ function update(state, action) {
32335
32809
  case "session_id":
32336
32810
  return __assign(__assign({}, state), { lastTimestamp: (_g = action.detail) === null || _g === void 0 ? void 0 : _g.timestamp, sessionId: action.detail.sessionId });
32337
32811
  case "visual_status":
32338
- return __assign(__assign({}, state), { lastTimestamp: (_h = action.detail) === null || _h === void 0 ? void 0 : _h.timestamp, visuals: __assign(__assign(__assign(__assign({}, (state.visuals || {})), (action.detail.status.drawer !== undefined && { drawer: action.detail.status.drawer })), (action.detail.status.opened !== undefined && { opened: action.detail.status.opened })), (action.detail.status.visible !== undefined && { visible: action.detail.status.visible })) });
32812
+ return __assign(__assign({}, state), { lastTimestamp: (_h = action.detail) === null || _h === void 0 ? void 0 : _h.timestamp, visuals: __assign(__assign(__assign(__assign(__assign({}, (state.visuals || {})), (action.detail.status.drawer !== undefined && { drawer: action.detail.status.drawer })), (action.detail.status.opened !== undefined && { opened: action.detail.status.opened })), (action.detail.status.visible !== undefined && { visible: action.detail.status.visible })), (action.detail.status.hasInteracted !== undefined && { hasInteracted: action.detail.status.hasInteracted })) });
32813
+ case "toggle_debug_mode":
32814
+ var newDebugMode = !state.debugMode;
32815
+ // Update localStorage to persist the setting
32816
+ if (typeof window !== 'undefined' && window.localStorage) {
32817
+ window.localStorage.setItem('xaErrorOverlay', newDebugMode ? 'enabled' : 'disabled');
32818
+ }
32819
+ return __assign(__assign({}, state), { debugMode: newDebugMode });
32339
32820
  case "department_update":
32340
32821
  return __assign(__assign({}, state), { lastTimestamp: (_j = action.detail) === null || _j === void 0 ? void 0 : _j.timestamp, departments: __assign(__assign({}, state.departments), (_a = {}, _a[action.detail.id] = __assign({}, action.detail), _a)) });
32341
32822
  case "visitor_update":
@@ -32486,6 +32967,8 @@ function createChatStore(config, dataStorage) {
32486
32967
  userId: config.userId,
32487
32968
  attributes: config.attributes,
32488
32969
  sessionExpiration: config.sessionExpiration
32970
+ }, {
32971
+ enableErrorOverlay: config.enableErrorOverlay
32489
32972
  });
32490
32973
  var chatReducer = persistStateReducer(storage, defaultState, storeHandler);
32491
32974
  // Configure store with @reduxjs/toolkit
@@ -32525,23 +33008,25 @@ function generateKey(connection, sessionId) {
32525
33008
  }
32526
33009
 
32527
33010
  var ChatWidgetContainer = function (props) {
32528
- var _a, _b, _c, _d, _e;
33011
+ var _a, _b, _c, _d, _e, _f;
32529
33012
  var messageMiddleware = useStandardMiddleware();
32530
33013
  var connection = useServerConfig(props.config);
32531
33014
  var chatStore = useMemo(function () {
32532
- var _a, _b, _c, _d;
33015
+ var _a, _b, _c, _d, _e;
32533
33016
  return createChatStore({
32534
33017
  connection: connection,
32535
33018
  userId: (_a = props.config) === null || _a === void 0 ? void 0 : _a.userId,
32536
33019
  accessToken: (_b = props.config) === null || _b === void 0 ? void 0 : _b.accessToken,
32537
33020
  attributes: (_c = props.config) === null || _c === void 0 ? void 0 : _c.attributes,
32538
- sessionExpiration: (_d = props.config) === null || _d === void 0 ? void 0 : _d.sessionExpiration
33021
+ sessionExpiration: (_d = props.config) === null || _d === void 0 ? void 0 : _d.sessionExpiration,
33022
+ enableErrorOverlay: (_e = props.config) === null || _e === void 0 ? void 0 : _e.enableErrorOverlay
32539
33023
  });
32540
- }, [connection, (_a = props.config) === null || _a === void 0 ? void 0 : _a.userId, (_b = props.config) === null || _b === void 0 ? void 0 : _b.accessToken, (_c = props.config) === null || _c === void 0 ? void 0 : _c.attributes, (_d = props.config) === null || _d === void 0 ? void 0 : _d.sessionExpiration]);
32541
- if ((_e = props.config) === null || _e === void 0 ? void 0 : _e.disabled) {
33024
+ }, [connection, (_a = props.config) === null || _a === void 0 ? void 0 : _a.userId, (_b = props.config) === null || _b === void 0 ? void 0 : _b.accessToken, (_c = props.config) === null || _c === void 0 ? void 0 : _c.attributes, (_d = props.config) === null || _d === void 0 ? void 0 : _d.sessionExpiration, (_e = props.config) === null || _e === void 0 ? void 0 : _e.enableErrorOverlay]);
33025
+ if ((_f = props.config) === null || _f === void 0 ? void 0 : _f.disabled) {
32542
33026
  return React$1.createElement(React$1.Fragment, null);
32543
33027
  }
32544
- var widgetProps = __assign(__assign({}, props), { messageMiddleware: messageMiddleware });
33028
+ var widgetProps = __assign(__assign({}, props), { messageMiddleware: messageMiddleware, getConfig: props.getConfig // Pass through getConfig callback
33029
+ });
32545
33030
  return (React$1.createElement(Provider, { store: chatStore },
32546
33031
  React$1.createElement(ChatWidgetWrapper, __assign({}, widgetProps))));
32547
33032
  };