@xapp/chat-widget 1.59.0 → 1.60.2

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
@@ -703,7 +703,7 @@ var CtaBubbleContainer = function (props) {
703
703
  };
704
704
 
705
705
  var ChatButton = function (props) {
706
- return (React__default$1["default"].createElement("button", { className: "xapp-chat-button ".concat(props.addClass || "").trim(), onClick: props.onClick },
706
+ return (React__default$1["default"].createElement("button", { "aria-label": "open chat", className: "xapp-chat-button ".concat(props.addClass || "").trim(), onClick: props.onClick },
707
707
  React__default$1["default"].createElement("div", { id: "xapp-widget-button", className: "xapp-chat-button__btn", style: props.borderStyle && {
708
708
  border: 'solid',
709
709
  borderWidth: props.borderStyle.width,
@@ -1082,6 +1082,14 @@ var LogChat = /** @class */ (function () {
1082
1082
  log("CLIENT: dispose:");
1083
1083
  this.inner.dispose();
1084
1084
  };
1085
+ LogChat.prototype.sleep = function () {
1086
+ log("CLIENT: sleep:");
1087
+ this.inner.sleep();
1088
+ };
1089
+ LogChat.prototype.wakeup = function () {
1090
+ log("CLIENT: wakeup:");
1091
+ this.inner.wakeup();
1092
+ };
1085
1093
  return LogChat;
1086
1094
  }());
1087
1095
 
@@ -2207,6 +2215,10 @@ var StentorDirectChat = /** @class */ (function () {
2207
2215
  };
2208
2216
  StentorDirectChat.prototype.dispose = function () {
2209
2217
  };
2218
+ StentorDirectChat.prototype.sleep = function () {
2219
+ };
2220
+ StentorDirectChat.prototype.wakeup = function () {
2221
+ };
2210
2222
  StentorDirectChat.prototype.postMessage = function (message) {
2211
2223
  var _a, _b, _c, _d, _e;
2212
2224
  return __awaiter$1(this, void 0, void 0, function () {
@@ -2468,6 +2480,10 @@ var StentorLocalChat = /** @class */ (function () {
2468
2480
  };
2469
2481
  StentorLocalChat.prototype.bargeIn = function () {
2470
2482
  };
2483
+ StentorLocalChat.prototype.sleep = function () {
2484
+ };
2485
+ StentorLocalChat.prototype.wakeup = function () {
2486
+ };
2471
2487
  return StentorLocalChat;
2472
2488
  }());
2473
2489
 
@@ -2606,9 +2622,21 @@ function requestToMessage(botRequest, now) {
2606
2622
  return responseMessage;
2607
2623
  }
2608
2624
 
2625
+ var ROUTER_USER = "router";
2626
+ var serverInfo = {
2627
+ deviceId: "Router",
2628
+ userId: ROUTER_USER,
2629
+ isAdmin: false,
2630
+ displayName: "XAPP Server",
2631
+ urlAttributes: {
2632
+ path: [],
2633
+ query: {}
2634
+ }
2635
+ };
2609
2636
  var StentorRouterChat = /** @class */ (function () {
2610
2637
  function StentorRouterChat(config, options) {
2611
2638
  var _a, _b;
2639
+ this.isDisposed = false;
2612
2640
  this._userId = "";
2613
2641
  this._sessionId = "";
2614
2642
  this.accessToken = "";
@@ -2621,10 +2649,10 @@ var StentorRouterChat = /** @class */ (function () {
2621
2649
  // Dig out the path parameters. Put them into the attributes.
2622
2650
  // The WS url is the barebone domain.
2623
2651
  var url = new URL(this.config.url);
2624
- var appId = url.searchParams.get("appId");
2652
+ this.appId = url.searchParams.get("appId");
2625
2653
  var locationUrl = new URL(window.location.href);
2626
2654
  this.isAdmin = locationUrl.searchParams.get("isAdmin") === "true";
2627
- if (appId) {
2655
+ if (this.appId) {
2628
2656
  // New Path if we have the appId on the query string
2629
2657
  this.serverUrl = this.config.url;
2630
2658
  this.urlAttributes.path = (_a = url.pathname) === null || _a === void 0 ? void 0 : _a.split("/");
@@ -2639,11 +2667,13 @@ var StentorRouterChat = /** @class */ (function () {
2639
2667
  this.urlAttributes.path = urlPath.slice(1);
2640
2668
  }
2641
2669
  }
2642
- log("WS url: ".concat(this.serverUrl, " isAdmin: ").concat(this.isAdmin, " attributes: ").concat(JSON.stringify(this.attributes)));
2670
+ log("WS url: ".concat(this.serverUrl, " isAdmin: ").concat(this.isAdmin, " attributes: ").concat(JSON.stringify(this.attributes), " appId: ").concat(this.appId));
2643
2671
  this.configurableMessages = getConfigurableMessagesConfig(options.configurableMessages);
2672
+ this.noOfServerErrors = 0;
2644
2673
  }
2645
2674
  StentorRouterChat.prototype.init = function (dispatch) {
2646
2675
  var _this = this;
2676
+ var _a, _b;
2647
2677
  this.dispatch = dispatch;
2648
2678
  this.setAccountStatus("offline");
2649
2679
  // Register "handlers" for the incoming events
@@ -2656,10 +2686,12 @@ var StentorRouterChat = /** @class */ (function () {
2656
2686
  }
2657
2687
  else {
2658
2688
  // Shut down
2689
+ err("SERVER: something is wrong. Going offline.");
2659
2690
  _this.dispatch(setAccountStatus("offline"));
2660
2691
  _this.dispatch(setConnectionStatus("offline"));
2661
2692
  }
2662
2693
  };
2694
+ // Server ping (not sent peroidically - at least not for now)
2663
2695
  this.handlers["account status"] = function (_data, _sender, ts) {
2664
2696
  dispatch({
2665
2697
  type: "account_status",
@@ -2670,7 +2702,7 @@ var StentorRouterChat = /** @class */ (function () {
2670
2702
  });
2671
2703
  };
2672
2704
  this.handlers["failure"] = function (data, sender, _ts) {
2673
- err("Router says something failed: type: ".concat(data.type, " tries: ").concat(data.tries, " error: ").concat(data.error));
2705
+ err("SERVER: something's failed: type: ".concat(data.type, " tries: ").concat(data.tries, " error: ").concat(data.error));
2674
2706
  var _a = _this.configurableMessages[data.tries], retry = _a.retry, delay = _a.delay, text = _a.text;
2675
2707
  _this.sendFailureMessage(retry, data.delay || delay, text, sender);
2676
2708
  };
@@ -2760,6 +2792,7 @@ var StentorRouterChat = /** @class */ (function () {
2760
2792
  });
2761
2793
  };
2762
2794
  this.handlers["disconnect"] = function () {
2795
+ err("SERVER: requested disconnect");
2763
2796
  _this.dispatch(setAccountStatus("offline"));
2764
2797
  _this.dispatch(setConnectionStatus("offline"));
2765
2798
  };
@@ -2768,24 +2801,46 @@ var StentorRouterChat = /** @class */ (function () {
2768
2801
  _this.dispatch(setConnectionStatus("online"));
2769
2802
  };
2770
2803
  this.handlers["reconnect failed"] = function (_data) {
2804
+ err("SERVER: says re-connect failed");
2771
2805
  _this.dispatch(setAccountStatus("offline"));
2772
2806
  _this.dispatch(setConnectionStatus("offline"));
2773
2807
  };
2774
2808
  this.handlers["reconnect error"] = function (_data) {
2809
+ err("SERVER: says there was an error while re-connecting");
2775
2810
  _this.dispatch(setAccountStatus("offline"));
2776
2811
  };
2812
+ // Register the router as a pseudo-agent (serverInfo) so it can send messages (like internal errors)
2813
+ this.dispatch({
2814
+ type: "chat",
2815
+ detail: {
2816
+ type: "chat.memberjoin",
2817
+ user: {
2818
+ avatarPath: (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.bot) === null || _b === void 0 ? void 0 : _b.avatarPath,
2819
+ displayName: serverInfo.displayName,
2820
+ nick: senderToNick(serverInfo),
2821
+ },
2822
+ timestamp: new Date().getTime(),
2823
+ },
2824
+ });
2777
2825
  // pretend we are online. The emit() will connect
2778
2826
  this.setAccountStatus("online");
2779
2827
  this.setConnectionStatus("online");
2780
2828
  };
2781
2829
  StentorRouterChat.prototype.autoReconnect = function (wsCreate) {
2782
2830
  var _this = this;
2831
+ if (this.noOfServerErrors === 0) {
2832
+ this.setConnectionStatus("pending");
2833
+ }
2783
2834
  var setActStatus = this.setAccountStatus.bind(this);
2784
2835
  var setConnStatus = this.setConnectionStatus.bind(this);
2785
2836
  function startReconnecting() {
2786
2837
  var interval = setInterval(function () {
2787
- log("Re-creating WS connection");
2788
2838
  var ws = wsCreate();
2839
+ if (!ws) {
2840
+ clearInterval(interval);
2841
+ return;
2842
+ }
2843
+ log("Re-created WS connection");
2789
2844
  ws.onopen = function () {
2790
2845
  log("Re-opened WS connection");
2791
2846
  // We are connected
@@ -2797,7 +2852,10 @@ var StentorRouterChat = /** @class */ (function () {
2797
2852
  }, 3000);
2798
2853
  }
2799
2854
  log("Creating WS connection");
2800
- wsCreate();
2855
+ var ws = wsCreate();
2856
+ if (!ws) {
2857
+ return;
2858
+ }
2801
2859
  this.ws.onclose = startReconnecting;
2802
2860
  this.ws.onopen = function () {
2803
2861
  log("Opened WS connection");
@@ -2808,7 +2866,10 @@ var StentorRouterChat = /** @class */ (function () {
2808
2866
  };
2809
2867
  StentorRouterChat.prototype.wsCreate = function () {
2810
2868
  var _this = this;
2811
- this.setConnectionStatus("pending");
2869
+ if (this.isDisposed) {
2870
+ log("Stopping reconnect for disposed router connector");
2871
+ return undefined;
2872
+ }
2812
2873
  var url = new URL(this.serverUrl);
2813
2874
  url.searchParams.set("userId", this._userId);
2814
2875
  url.searchParams.set("isAdmin", "".concat(this.isAdmin));
@@ -2816,8 +2877,6 @@ var StentorRouterChat = /** @class */ (function () {
2816
2877
  this.ws.onerror = function (ev) {
2817
2878
  var _a;
2818
2879
  err("Error in WS connection. Url: ".concat(url.toString(), " Type: ").concat(!ev ? "?" : ev.type, " Ready State: ").concat((_a = _this.ws) === null || _a === void 0 ? void 0 : _a.readyState));
2819
- // TODO: Experimental. Let's not set it to "pending". We may have a timing issue and miss the "online"
2820
- // this.setConnectionStatus("pending");
2821
2880
  };
2822
2881
  this.ws.onmessage = function (me) {
2823
2882
  log("ROUTER says: ".concat(me.data));
@@ -2833,7 +2892,8 @@ var StentorRouterChat = /** @class */ (function () {
2833
2892
  return this.ws;
2834
2893
  };
2835
2894
  StentorRouterChat.prototype.checkConnection = function () {
2836
- return this.ws.readyState === WebSocket.OPEN;
2895
+ var _a;
2896
+ return ((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN;
2837
2897
  };
2838
2898
  StentorRouterChat.prototype.emit = function (event, data) {
2839
2899
  return __awaiter$1(this, void 0, void 0, function () {
@@ -2860,9 +2920,11 @@ var StentorRouterChat = /** @class */ (function () {
2860
2920
  log("Connection is ready in ".concat(t, " ms"));
2861
2921
  }
2862
2922
  _this.ws.send(payloadData);
2923
+ _this.noOfServerErrors = 0;
2863
2924
  })
2864
2925
  .catch(function (t) {
2865
- err("Connection wait timed out in ".concat(t, " ms"));
2926
+ err("Connection wait timed out in ".concat(t, " ms (show error)"));
2927
+ _this.setConnectionStatus("online");
2866
2928
  })];
2867
2929
  case 1:
2868
2930
  _a.sent();
@@ -2919,6 +2981,24 @@ var StentorRouterChat = /** @class */ (function () {
2919
2981
  }
2920
2982
  });
2921
2983
  };
2984
+ StentorRouterChat.prototype.sendDisconnectMessage = function () {
2985
+ this.dispatch({
2986
+ type: "chat",
2987
+ detail: {
2988
+ type: "chat.msg",
2989
+ user: {
2990
+ displayName: "Server",
2991
+ nick: senderToNick(serverInfo),
2992
+ avatarPath: serverInfo.avatarPath
2993
+ },
2994
+ msg: { text: this.noOfServerErrors === 0 ?
2995
+ "I cannot connect to the server. Please try later." :
2996
+ "Nope. Still no luck. I still cannot connect to the server. Please don't give up." },
2997
+ timestamp: new Date().getTime(),
2998
+ }
2999
+ });
3000
+ this.noOfServerErrors++;
3001
+ };
2922
3002
  StentorRouterChat.prototype.checkSession = function () {
2923
3003
  return this.sessionCreated;
2924
3004
  };
@@ -2927,18 +3007,31 @@ var StentorRouterChat = /** @class */ (function () {
2927
3007
  var _this = this;
2928
3008
  return __generator$1(this, function (_a) {
2929
3009
  switch (_a.label) {
2930
- case 0: return [4 /*yield*/, waitFor(this.checkSession.bind(this), 500, 5000, "session creation")
2931
- .then(function (t) {
2932
- if (t > 0) {
2933
- log("Session creation is ready in ".concat(t, " ms"));
2934
- }
2935
- _this.postMessage(serviceRequest);
2936
- })
2937
- .catch(function (t) {
2938
- err("Session creation wait timed out in ".concat(t, " ms"));
2939
- })];
3010
+ case 0:
3011
+ if (!(this.checkConnection() && !this.checkSession())) return [3 /*break*/, 2];
3012
+ return [4 /*yield*/, this.postVisitorInfo()];
2940
3013
  case 1:
2941
3014
  _a.sent();
3015
+ _a.label = 2;
3016
+ case 2:
3017
+ if (!this.checkSession()) {
3018
+ this.setConnectionStatus("pending");
3019
+ }
3020
+ return [4 /*yield*/, waitFor(this.checkSession.bind(this), 500, 5000, "session creation")
3021
+ .then(function (t) {
3022
+ if (t > 0) {
3023
+ log("Session creation is ready in ".concat(t, " ms"));
3024
+ }
3025
+ _this.postMessage(serviceRequest);
3026
+ })
3027
+ .catch(function (t) {
3028
+ err("Session creation wait timed out in ".concat(t, " ms"));
3029
+ _this.setConnectionStatus("online"); // stop pulsing
3030
+ _this.sendDisconnectMessage();
3031
+ })];
3032
+ case 3:
3033
+ _a.sent();
3034
+ this.setConnectionStatus("online");
2942
3035
  cb();
2943
3036
  return [2 /*return*/];
2944
3037
  }
@@ -2973,7 +3066,26 @@ var StentorRouterChat = /** @class */ (function () {
2973
3066
  // mark the messages read
2974
3067
  };
2975
3068
  StentorRouterChat.prototype.flush = function () { };
2976
- StentorRouterChat.prototype.dispose = function () { };
3069
+ StentorRouterChat.prototype.dispose = function () {
3070
+ this.isDisposed = true;
3071
+ this.ws.close();
3072
+ log("Closed web socket (dispose)");
3073
+ };
3074
+ StentorRouterChat.prototype.sleep = function () {
3075
+ this.isDisposed = true;
3076
+ this.ws.close();
3077
+ log("Closed web socket (dispose)");
3078
+ };
3079
+ StentorRouterChat.prototype.wakeup = function () {
3080
+ // wait for the session setup
3081
+ if (!this._userId) {
3082
+ return;
3083
+ }
3084
+ this.isDisposed = false;
3085
+ // Fire up the WebSocket
3086
+ this.autoReconnect(this.wsCreate.bind(this));
3087
+ log("Waking up");
3088
+ };
2977
3089
  StentorRouterChat.prototype.bargeOut = function (_cb) {
2978
3090
  return __awaiter$1(this, void 0, void 0, function () {
2979
3091
  return __generator$1(this, function (_a) {
@@ -6605,6 +6717,10 @@ var StentorServerChat = /** @class */ (function () {
6605
6717
  var _a;
6606
6718
  (_a = this.socket) === null || _a === void 0 ? void 0 : _a.disconnect();
6607
6719
  };
6720
+ StentorServerChat.prototype.sleep = function () {
6721
+ };
6722
+ StentorServerChat.prototype.wakeup = function () {
6723
+ };
6608
6724
  StentorServerChat.prototype.bargeOut = function (_cb) {
6609
6725
  return __awaiter$1(this, void 0, void 0, function () {
6610
6726
  return __generator$1(this, function (_a) {
@@ -30332,6 +30448,10 @@ var QueuePosition = function (props) {
30332
30448
  props.position)));
30333
30449
  };
30334
30450
 
30451
+ function isServerUser(user) {
30452
+ var _a;
30453
+ return (_a = user.nick) === null || _a === void 0 ? void 0 : _a.endsWith(ROUTER_USER);
30454
+ }
30335
30455
  function getMessageByType(msg) {
30336
30456
  switch (msg.type) {
30337
30457
  case "chat.memberjoin":
@@ -30351,9 +30471,14 @@ function getMessageByType(msg) {
30351
30471
  }
30352
30472
  }
30353
30473
  var SystemMessage = function (props) {
30354
- return (React__default$1["default"].createElement("div", { className: "system-msg-container" },
30355
- React__default$1["default"].createElement("span", { className: "message-sr-only" }, "at " + props.time + " system message"),
30356
- React__default$1["default"].createElement("span", { className: "system-msg" }, getMessageByType(props.message))));
30474
+ if (!isServerUser(props.message.user)) {
30475
+ return (React__default$1["default"].createElement("div", { className: "system-msg-container" },
30476
+ React__default$1["default"].createElement("span", { className: "message-sr-only" }, "at " + props.time + " system message"),
30477
+ React__default$1["default"].createElement("span", { className: "system-msg" }, getMessageByType(props.message))));
30478
+ }
30479
+ else {
30480
+ return null;
30481
+ }
30357
30482
  };
30358
30483
  function convertToSentenceCase(s) {
30359
30484
  return s[0].toUpperCase() + s.slice(1);
@@ -30482,6 +30607,7 @@ var MessageList = function (props) {
30482
30607
  }
30483
30608
  return props.messages.map(function (message, index) {
30484
30609
  // const next = props.messages[index + 1];
30610
+ var _a, _b;
30485
30611
  // let sibling = false;
30486
30612
  // const currentNick = message.nick;
30487
30613
  // const prevNick = next && next.nick;
@@ -30502,9 +30628,9 @@ var MessageList = function (props) {
30502
30628
  "chat.offline",
30503
30629
  "chat.prechat"
30504
30630
  ];
30505
- // show first and las TS and after at least 5 minutes gap
30631
+ // show first and las TS and after at least 5 minutes gap. Don't show "router user"
30506
30632
  var showTs = false;
30507
- if (tsTypes.includes(message.type)) {
30633
+ if (tsTypes.includes(message.type) && !((_b = (_a = message.user) === null || _a === void 0 ? void 0 : _a.nick) === null || _b === void 0 ? void 0 : _b.endsWith(ROUTER_USER))) {
30508
30634
  if (index === 0 || index === props.messages.length - 1 || index === lastMsgIndex) {
30509
30635
  showTs = true;
30510
30636
  }
@@ -30863,7 +30989,7 @@ var ChatWidget = function (props) {
30863
30989
  var canRefresh = (_c = (_b = props.config.header) === null || _b === void 0 ? void 0 : _b.actions) === null || _c === void 0 ? void 0 : _c.refresh;
30864
30990
  // can't minimize in docked mode or static mode.
30865
30991
  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);
30866
- console.log("".concat(dockedMode, " ").concat(staticMode, " ").concat((_g = (_f = props.config.header) === null || _f === void 0 ? void 0 : _f.actions) === null || _g === void 0 ? void 0 : _g.minimize));
30992
+ 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));
30867
30993
  var canCancel;
30868
30994
  // To preserve legacy behavior, cancel needs a little more checks
30869
30995
  if (typeof ((_j = (_h = props.config.header) === null || _h === void 0 ? void 0 : _h.actions) === null || _j === void 0 ? void 0 : _j.cancel) === "boolean") {
@@ -30915,6 +31041,28 @@ var ChatWidget = function (props) {
30915
31041
  }
30916
31042
  // eslint-disable-next-line react-hooks/exhaustive-deps
30917
31043
  }, []);
31044
+ var _5 = React$1.useState(!document.hidden), isTabVisible = _5[0], setIsTabVisible = _5[1];
31045
+ React$1.useEffect(function () {
31046
+ var handleVisibilityChange = function () {
31047
+ setIsTabVisible(!document.hidden);
31048
+ };
31049
+ document.addEventListener('visibilitychange', handleVisibilityChange);
31050
+ return function () {
31051
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
31052
+ };
31053
+ }, []);
31054
+ React$1.useEffect(function () {
31055
+ // Too early?
31056
+ if (!chatServer) {
31057
+ return;
31058
+ }
31059
+ if (!isTabVisible) {
31060
+ chatServer.sleep();
31061
+ }
31062
+ else {
31063
+ chatServer.wakeup();
31064
+ }
31065
+ }, [chatServer, innerDispatch, isTabVisible]);
30918
31066
  React$1.useEffect(function () {
30919
31067
  // For reopen widget after move on same windowyar
30920
31068
  // if (get("opened")) {
@@ -31025,38 +31173,6 @@ var ChatWidget = function (props) {
31025
31173
  }
31026
31174
  var isOffline = chatState.accountStatus === "offline" && !chatState.isChatting;
31027
31175
  var messages = chatState && chatState.chats;
31028
- if (isOffline) {
31029
- messages.push({
31030
- type: "chat.msg",
31031
- user: {
31032
- displayName: "Chat Agent",
31033
- nick: "agent:offline"
31034
- },
31035
- timestamp: +new Date(),
31036
- msg: {
31037
- text: "Sorry, we are offline at the moment. Please leave us your contact information and we will get back to you soon!"
31038
- }
31039
- });
31040
- messages.push({
31041
- type: "chat.offline",
31042
- user: {
31043
- nick: "agent:offline"
31044
- },
31045
- timestamp: +new Date()
31046
- });
31047
- }
31048
- else if (!chatState.isChatting) {
31049
- messages.length = 0; // clear the list
31050
- if (props.preChatFormEnabled) {
31051
- messages.push({
31052
- type: "chat.prechat",
31053
- user: {
31054
- nick: "agent:offline"
31055
- },
31056
- timestamp: +new Date()
31057
- });
31058
- }
31059
- }
31060
31176
  var config = props.config, onConnectionStatusChange = props.onConnectionStatusChange;
31061
31177
  useGreeting(!isOffline && !props.preChatFormEnabled && visible);
31062
31178
  var connectionStatus = chatState.connection.connectionStatus;