@eshal-bot/chat-widget 0.2.20 → 0.2.21

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.
@@ -1 +1 @@
1
- export{e as default}from"./chat-widget-index-CjJ4shXp.esm.js";import"react";import"react-dom/client";import"react/jsx-runtime";import"react-dom";
1
+ export{e as default}from"./chat-widget-index-BcyXZWaW.esm.js";import"react";import"react-dom/client";import"react/jsx-runtime";import"react-dom";
@@ -8391,7 +8391,13 @@
8391
8391
  stale: s.stale
8392
8392
  })).filter(s => s.source_id || s.url || s.source_type === 'database') : [];
8393
8393
  };
8394
- const processStream = async (stream, setMessages, onTerminal) => {
8394
+
8395
+ /**
8396
+ * @param {Function} [onHumanHandoff] - called when the server answers with the
8397
+ * human_handoff marker: a person owns the conversation, so the caller starts
8398
+ * listening for their replies (and anything else pushed to the widget).
8399
+ */
8400
+ const processStream = async (stream, setMessages, onTerminal, onHumanHandoff) => {
8395
8401
  const updateMessage = createMessageUpdater(setMessages);
8396
8402
  const reader = stream.getReader();
8397
8403
  const decoder = new TextDecoder();
@@ -8509,6 +8515,7 @@
8509
8515
  // human agent's reply arrives via the SSE EventSource instead.
8510
8516
  if (parsed.type === 'human_handoff') {
8511
8517
  markTerminal();
8518
+ if (typeof onHumanHandoff === 'function') onHumanHandoff();
8512
8519
  continue;
8513
8520
  }
8514
8521
 
@@ -12281,6 +12288,11 @@
12281
12288
  // over the SSE EventSource instead. The ref mirrors the state for a
12282
12289
  // synchronous read inside sendMessage (whose useCallback deps are fixed).
12283
12290
  const [isHandedOff, setIsHandedOff] = reactExports.useState(false);
12291
+ // A rating an agent asked for from the Inbox (backend
12292
+ // services/csatRequest.ts): { format, prompt, requestedAt }, or null. Set by
12293
+ // the live csat_request event, or by /history when the widget was not
12294
+ // listening at the time; the chat window shows its rating card for it.
12295
+ const [csatRequest, setCsatRequest] = reactExports.useState(null);
12284
12296
  const isHandedOffRef = reactExports.useRef(false);
12285
12297
  const markHandedOff = reactExports.useCallback(() => {
12286
12298
  isHandedOffRef.current = true;
@@ -12483,6 +12495,11 @@
12483
12495
  try {
12484
12496
  const data = JSON.parse(event.data);
12485
12497
  // Erased in the console while open: stop listening and start over.
12498
+ // An agent asked this visitor for a rating.
12499
+ if (data.type === 'csat_request' && data.csat) {
12500
+ setCsatRequest(data.csat);
12501
+ return;
12502
+ }
12486
12503
  if (data.type === 'conversation_erased') {
12487
12504
  es.close();
12488
12505
  if (handoffEventSourceRef.current === es) handoffEventSourceRef.current = null;
@@ -12779,6 +12796,8 @@
12779
12796
  const data = await res.json();
12780
12797
  const serverMsgs = Array.isArray(data?.messages) ? data.messages : [];
12781
12798
  const agentMsgs = serverMsgs.filter(isRepliedOutsideStream);
12799
+ // An open rating request sent while this widget was not listening.
12800
+ if (!cancelled && data?.csatRequest) setCsatRequest(data.csatRequest);
12782
12801
 
12783
12802
  // Merge past human-agent replies into the transcript (regardless of
12784
12803
  // current responder - they're real history worth showing). Shares
@@ -13269,7 +13288,14 @@
13269
13288
  // it unable to type their next question. Retries are unaffected:
13270
13289
  // IncompleteStreamError is only thrown when NO terminal event
13271
13290
  // arrived, so nothing that reaches this callback is ever retried.
13272
- await processStream(stream, setMessages, releaseComposer);
13291
+ await processStream(stream, setMessages, releaseComposer, () => {
13292
+ // The server says a person owns this conversation (an agent
13293
+ // took it over from the Inbox): listen for their replies, as
13294
+ // the hand-off path already expects, with EV-4047's backfill
13295
+ // catching anything sent before the stream opened.
13296
+ markHandedOff();
13297
+ void startHandoffEventSource();
13298
+ });
13273
13299
  setUserMessageStatus(sentUserMessageId, "sent");
13274
13300
  updateActivity(organizationId);
13275
13301
  return {
@@ -14695,6 +14721,8 @@
14695
14721
  // Reset messages
14696
14722
  setMessages([]);
14697
14723
  setBidiMessages([]);
14724
+ // The rating request belonged to the conversation being left.
14725
+ setCsatRequest(null);
14698
14726
 
14699
14727
  // Drop the localStorage transcript for the conversation we're abandoning
14700
14728
  // BEFORE we rotate to a fresh sessionId, otherwise the old bucket leaks.
@@ -14943,7 +14971,9 @@
14943
14971
  // Session lifecycle
14944
14972
  sessionExpiringSoon,
14945
14973
  resetConversation,
14946
- updateMessageFeedback
14974
+ updateMessageFeedback,
14975
+ // Rating request from the Inbox (null when none is open).
14976
+ csatRequest
14947
14977
  };
14948
14978
  };
14949
14979
 
@@ -20720,6 +20750,9 @@
20720
20750
  csatEnabled = false,
20721
20751
  csatFormat = "EMOJI",
20722
20752
  csatPrompt = "How was your experience?",
20753
+ // A rating an agent asked for from the Inbox: { format, prompt } or null.
20754
+ // Shown whether or not the automatic survey (csatEnabled) is on.
20755
+ csatRequest = null,
20723
20756
  onPromptSuggestionClick,
20724
20757
  onboardingEnabled = false,
20725
20758
  onResetConversation,
@@ -21034,7 +21067,7 @@
21034
21067
  const handleCsatRating = async (rating, format) => {
21035
21068
  setCsatSubmitted(true); // optimistic UI
21036
21069
  setShowCsat(false);
21037
- markCsatSubmitted(undefined); // persist so page refresh doesn't re-show CSAT
21070
+ markCsatSubmitted(organizationId); // persist so page refresh doesn't re-show CSAT
21038
21071
 
21039
21072
  try {
21040
21073
  const headers = {
@@ -21512,11 +21545,12 @@
21512
21545
  label: t("chooseTopicLabel")
21513
21546
  }) : null,
21514
21547
  quickQuestionsHeadingLabel: filterEnabled ? t("quickQuestionsHeadingLabel") : undefined
21515
- }), showCsat && csatEnabled && !csatSubmitted && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
21548
+ }), (showCsat && csatEnabled || csatRequest) && !csatSubmitted && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
21516
21549
  className: "",
21550
+ "data-testid": "widget-csat-card",
21517
21551
  children: /*#__PURE__*/jsxRuntimeExports.jsx(CSATWidget, {
21518
- format: normalizeCsatFormat(csatFormat),
21519
- prompt: csatPrompt || t("howWasYourExperience"),
21552
+ format: normalizeCsatFormat(csatRequest?.format || csatFormat),
21553
+ prompt: csatRequest?.prompt || csatPrompt || t("howWasYourExperience"),
21520
21554
  onRating: handleCsatRating,
21521
21555
  disabled: false,
21522
21556
  isDark: isDark,
@@ -21866,7 +21900,7 @@
21866
21900
  * value by its own test (that constant sat at 0.1.113 while this package was
21867
21901
  * at 0.2.2 precisely because nothing enforced it - EV-2431).
21868
21902
  */
21869
- const WIDGET_VERSION = '0.2.20';
21903
+ const WIDGET_VERSION = '0.2.21';
21870
21904
 
21871
21905
  /**
21872
21906
  * API utility functions
@@ -22273,7 +22307,8 @@
22273
22307
  // CategoryTabsBar / CategoryFilterInline components in ChatWindow.
22274
22308
  widgetFilter,
22275
22309
  setWidgetFilter,
22276
- addAssistantMessage
22310
+ addAssistantMessage,
22311
+ csatRequest
22277
22312
  } = useChatState(widgetConfig ? {
22278
22313
  welcomeMessage: widgetConfig.welcomeMessage,
22279
22314
  // Per the EV-3813 note below, this hook produces customer-facing
@@ -22496,6 +22531,7 @@
22496
22531
  csatEnabled: widgetConfig.csatEnabled,
22497
22532
  csatFormat: widgetConfig.csatFormat,
22498
22533
  csatPrompt: widgetConfig.csatPrompt,
22534
+ csatRequest: csatRequest,
22499
22535
  onboardingEnabled: widgetConfig.onboardingEnabled,
22500
22536
  onResetConversation: resetConversation,
22501
22537
  sessionExpiringSoon: sessionExpiringSoon,