@eshal-bot/chat-widget 0.2.34 → 0.2.36

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.
@@ -8060,6 +8060,48 @@
8060
8060
  return response.json();
8061
8061
  };
8062
8062
 
8063
+ /**
8064
+ * Widget verification codes (POST /api/v1/support/identity/start|verify).
8065
+ * The code is posted here, never as a chat message, so it never reaches the
8066
+ * model or the transcript. Resolves to { ok, status, body } so the card can
8067
+ * show the server's own wording (tries left, locked, expired).
8068
+ */
8069
+ const postIdentity = async (path, payload, apiBaseUrl, getAuthToken) => {
8070
+ const headers = {
8071
+ 'Content-Type': 'application/json'
8072
+ };
8073
+ if (typeof getAuthToken === 'function') {
8074
+ const token = await getAuthToken();
8075
+ if (token) headers['Authorization'] = `Bearer ${token}`;
8076
+ }
8077
+ const response = await fetch(`${apiBaseUrl.replace(/\/$/, '')}/api/v1/support/identity/${path}`, {
8078
+ method: 'POST',
8079
+ headers,
8080
+ credentials: 'include',
8081
+ body: JSON.stringify(payload)
8082
+ });
8083
+ let body = {};
8084
+ try {
8085
+ body = await response.json();
8086
+ } catch {
8087
+ body = {};
8088
+ }
8089
+ return {
8090
+ ok: response.ok,
8091
+ status: response.status,
8092
+ body
8093
+ };
8094
+ };
8095
+
8096
+ /** @param {{ conversationId: string, method: 'email'|'sms', email?: string, phone?: string }} payload */
8097
+ const startVisitorVerification = (payload, apiBaseUrl, getAuthToken) => postIdentity('start', payload, apiBaseUrl, getAuthToken);
8098
+
8099
+ /** @param {{ conversationId: string, code: string }} payload */
8100
+ const verifyVisitorCode = (payload, apiBaseUrl, getAuthToken) => postIdentity('verify', payload, apiBaseUrl, getAuthToken);
8101
+
8102
+ /** Delivery of the pending code ("sent", "delivered", "failed" or null). */
8103
+ const visitorCodeStatus = (payload, apiBaseUrl, getAuthToken) => postIdentity('status', payload, apiBaseUrl, getAuthToken);
8104
+
8063
8105
  // ============================================================================
8064
8106
  // UI HELPERS
8065
8107
  // ============================================================================
@@ -9245,7 +9287,28 @@
9245
9287
  // that dies on the wire (e.g. the network changed mid-request) used to
9246
9288
  // render exactly like a delivered message.
9247
9289
  messageNotDelivered: "Not delivered",
9248
- retrySend: "Retry"
9290
+ retrySend: "Retry",
9291
+ // Verification code card. EN-only for now - translate() falls back to EN
9292
+ // for locales without the key.
9293
+ verifyTitle: "Confirm it's you",
9294
+ verifyEmailLabel: "Your email",
9295
+ verifyPhoneLabel: "Your mobile number",
9296
+ verifySendCode: "Send code",
9297
+ verifySending: "Sending...",
9298
+ verifyEnterCode: "Enter the code we sent to {target}",
9299
+ verifyCodeLabel: "6-digit code",
9300
+ verifyConfirm: "Confirm",
9301
+ verifyResendIn: "Resend in {seconds} s",
9302
+ verifyResend: "Send a new code",
9303
+ verifyDifferent: "Use a different address",
9304
+ verifyDone: "Verified as {target}",
9305
+ verifyResumeMessage: "I've confirmed it's me.",
9306
+ verifyTriesLeft: "That code doesn't match. {count} tries left.",
9307
+ verifyGenericError: "Something went wrong. Try again.",
9308
+ verifyInputBlocked: "Enter your code above to continue",
9309
+ verifyCancel: "Cancel",
9310
+ verifyCancelled: "Verification cancelled.",
9311
+ verifyNotDelivered: "We couldn't deliver the code to that number. Check it and send a new code."
9249
9312
  };
9250
9313
  const DICTIONARIES = {
9251
9314
  en: EN,
@@ -12098,25 +12161,37 @@
12098
12161
  attachmentLimitReached: "That file is too large. This chat can receive up to {max_mb} MB of files in total.",
12099
12162
  attachmentLimitReachedUsed: "That file is too large. This chat can receive up to {max_mb} MB of files in total, and {used_mb} MB is already used.",
12100
12163
  attachmentFileTooLarge: "Sorry, that file is too large. Files must be under {max_mb} MB.",
12101
- attachmentTypeNotAllowed: "Sorry, we can't accept that type of file. You can send {types}."
12164
+ attachmentTypeNotAllowed: "Sorry, we can't accept that type of file. You can send {types}.",
12165
+ attachmentLimitReachedSize: "That file is {file_mb} MB, which is too large. This chat can receive up to {max_mb} MB of files in total.",
12166
+ attachmentLimitReachedUsedSize: "That file is {file_mb} MB, which is too large. This chat can receive up to {max_mb} MB of files in total, and {used_mb} MB is already used.",
12167
+ attachmentFileTooLargeSize: "Sorry, that file is {file_mb} MB, which is too large. Files must be under {max_mb} MB."
12102
12168
  },
12103
12169
  ar: {
12104
12170
  attachmentLimitReached: "حجم الملف كبير جداً. يمكن لهذه المحادثة استقبال ملفات يصل مجموع حجمها إلى {max_mb} ميغابايت.",
12105
12171
  attachmentLimitReachedUsed: "حجم الملف كبير جداً. يمكن لهذه المحادثة استقبال ملفات يصل مجموع حجمها إلى {max_mb} ميغابايت، وقد تم استخدام {used_mb} ميغابايت.",
12106
12172
  attachmentFileTooLarge: "عذراً، حجم الملف كبير جداً. يجب أن يكون حجم الملف أقل من {max_mb} ميغابايت.",
12107
- attachmentTypeNotAllowed: "عذراً، لا يمكننا استقبال هذا النوع من الملفات. يمكنك إرسال: {types}."
12173
+ attachmentTypeNotAllowed: "عذراً، لا يمكننا استقبال هذا النوع من الملفات. يمكنك إرسال: {types}.",
12174
+ attachmentLimitReachedSize: "حجم الملف {file_mb} ميغابايت، وهو كبير جداً. يمكن لهذه المحادثة استقبال ملفات يصل مجموع حجمها إلى {max_mb} ميغابايت.",
12175
+ attachmentLimitReachedUsedSize: "حجم الملف {file_mb} ميغابايت، وهو كبير جداً. يمكن لهذه المحادثة استقبال ملفات يصل مجموع حجمها إلى {max_mb} ميغابايت، وقد تم استخدام {used_mb} ميغابايت.",
12176
+ attachmentFileTooLargeSize: "عذراً، حجم الملف {file_mb} ميغابايت، وهو كبير جداً. يجب أن يكون حجم الملف أقل من {max_mb} ميغابايت."
12108
12177
  },
12109
12178
  zh: {
12110
12179
  attachmentLimitReached: "文件过大。此聊天最多可接收共 {max_mb} MB 的文件。",
12111
12180
  attachmentLimitReachedUsed: "文件过大。此聊天最多可接收共 {max_mb} MB 的文件,目前已使用 {used_mb} MB。",
12112
12181
  attachmentFileTooLarge: "抱歉,文件过大。文件大小必须小于 {max_mb} MB。",
12113
- attachmentTypeNotAllowed: "抱歉,无法接收此类文件。您可以发送:{types}。"
12182
+ attachmentTypeNotAllowed: "抱歉,无法接收此类文件。您可以发送:{types}。",
12183
+ attachmentLimitReachedSize: "该文件为 {file_mb} MB,过大。此聊天最多可接收共 {max_mb} MB 的文件。",
12184
+ attachmentLimitReachedUsedSize: "该文件为 {file_mb} MB,过大。此聊天最多可接收共 {max_mb} MB 的文件,目前已使用 {used_mb} MB。",
12185
+ attachmentFileTooLargeSize: "抱歉,该文件为 {file_mb} MB,过大。文件大小必须小于 {max_mb} MB。"
12114
12186
  },
12115
12187
  ja: {
12116
12188
  attachmentLimitReached: "ファイルが大きすぎます。このチャットで受け取れるファイルは合計 {max_mb} MB までです。",
12117
12189
  attachmentLimitReachedUsed: "ファイルが大きすぎます。このチャットで受け取れるファイルは合計 {max_mb} MB までで、すでに {used_mb} MB を使用しています。",
12118
12190
  attachmentFileTooLarge: "申し訳ありませんが、ファイルが大きすぎます。ファイルは {max_mb} MB 未満にしてください。",
12119
- attachmentTypeNotAllowed: "申し訳ありませんが、この種類のファイルは受け付けていません。送信できるファイル: {types}"
12191
+ attachmentTypeNotAllowed: "申し訳ありませんが、この種類のファイルは受け付けていません。送信できるファイル: {types}",
12192
+ attachmentLimitReachedSize: "このファイルは {file_mb} MB で、大きすぎます。このチャットで受け取れるファイルは合計 {max_mb} MB までです。",
12193
+ attachmentLimitReachedUsedSize: "このファイルは {file_mb} MB で、大きすぎます。このチャットで受け取れるファイルは合計 {max_mb} MB までで、すでに {used_mb} MB を使用しています。",
12194
+ attachmentFileTooLargeSize: "申し訳ありませんが、このファイルは {file_mb} MB で、大きすぎます。ファイルは {max_mb} MB 未満にしてください。"
12120
12195
  }
12121
12196
  };
12122
12197
  function translate(locale, key) {
@@ -14014,6 +14089,11 @@
14014
14089
  ...(opts?.toolConfirmation ? {
14015
14090
  tool_confirmation: opts.toolConfirmation
14016
14091
  } : {}),
14092
+ // Verification code card: the held personal tool may run now. The
14093
+ // code itself was posted to /support/identity, not here.
14094
+ ...(opts?.verificationComplete ? {
14095
+ verification_complete: opts.verificationComplete
14096
+ } : {}),
14017
14097
  messageHistory: messages.filter(msg => {
14018
14098
  // Filter out processing messages, empty messages, and onboarding messages
14019
14099
  return !msg.isProcessing && msg.content && msg.content.trim() && !['userName', 'email', 'phone'].includes(msg.type);
@@ -18955,6 +19035,13 @@
18955
19035
  const v = Math.max(0, Number(bytes) || 0) / (1024 * 1024);
18956
19036
  return v >= 10 ? String(Math.round(v)) : String(Math.round(v * 10) / 10);
18957
19037
  };
19038
+ // EV-4701: the refused file's own size, so the customer sees why it did not
19039
+ // fit. One decimal below 100 MB, so a 10.4 MB file never reads as "10 MB"
19040
+ // against a 10 MB limit.
19041
+ const fileMb = bytes => {
19042
+ const v = Math.max(0, Number(bytes) || 0) / (1024 * 1024);
19043
+ return v >= 100 ? String(Math.round(v)) : String(Math.round(v * 10) / 10);
19044
+ };
18958
19045
 
18959
19046
  /**
18960
19047
  * The agent's reply to a rejected file, in the widget's language.
@@ -18969,16 +19056,23 @@
18969
19056
  types: types || "PDF"
18970
19057
  });
18971
19058
  }
19059
+ // With the file's size known the message names it; without it, as before.
19060
+ const size = Number(rejection.size) || 0;
19061
+ const sized = key => size > 0 ? `${key}Size` : key;
19062
+ const file_mb = fileMb(size);
18972
19063
  if (rejection.code === "file_too_large") {
18973
- return fill(t("attachmentFileTooLarge"), {
19064
+ return fill(t(sized("attachmentFileTooLarge")), {
19065
+ file_mb,
18974
19066
  max_mb: String(config.fileUploadMaxFileMB ?? maxMb)
18975
19067
  });
18976
19068
  }
18977
19069
  const used = Number(rejection.usedBytes) || 0;
18978
- return used > 0 ? fill(t("attachmentLimitReachedUsed"), {
19070
+ return used > 0 ? fill(t(sized("attachmentLimitReachedUsed")), {
19071
+ file_mb,
18979
19072
  max_mb: maxMb,
18980
19073
  used_mb: mb(used)
18981
- }) : fill(t("attachmentLimitReached"), {
19074
+ }) : fill(t(sized("attachmentLimitReached")), {
19075
+ file_mb,
18982
19076
  max_mb: maxMb
18983
19077
  });
18984
19078
  }
@@ -19825,6 +19919,9 @@
19825
19919
  isMinimized,
19826
19920
  isLoading,
19827
19921
  isConversationLoading = false,
19922
+ // A verification code card is waiting for its code: the visitor finishes
19923
+ // (or cancels) it before typing, so a code is never typed into the chat.
19924
+ verificationPending = false,
19828
19925
  placeholder,
19829
19926
  textColor,
19830
19927
  fontFamily,
@@ -20028,7 +20125,7 @@
20028
20125
  // (so a user can upload a file and hit Send without typing). When
20029
20126
  // uploads are in flight we block Send to prevent partial payloads.
20030
20127
  const hasReadyAttachment = attachments.some(a => a.status === "ready");
20031
- const isDisabled = !inputValue.trim() && !hasReadyAttachment || isLoading || isConversationLoading || isUploadBusy;
20128
+ const isDisabled = !inputValue.trim() && !hasReadyAttachment || isLoading || isConversationLoading || isUploadBusy || verificationPending;
20032
20129
  const handleKeyPress = event => {
20033
20130
  if (event.key === "Enter" && !event.shiftKey) {
20034
20131
  event.preventDefault();
@@ -20039,6 +20136,7 @@
20039
20136
  // session - so the file is ingested into the shared session store and
20040
20137
  // answered, and later spoken turns in the same session see it too. A
20041
20138
  // plain voice turn (no attachment) still goes over the WS.
20139
+ if (verificationPending) return;
20042
20140
  if (isVoiceSessionActive && onBidiSubmit && !hasReadyAttachment) {
20043
20141
  onBidiSubmit();
20044
20142
  return;
@@ -20285,9 +20383,9 @@
20285
20383
  onFocus: () => setIsFocused(true),
20286
20384
  onBlur: () => setIsFocused(false),
20287
20385
  onKeyDown: handleKeyPress,
20288
- placeholder: isConversationLoading ? t("agentIsLoading") : placeholder || t("typeYourMessage"),
20386
+ placeholder: isConversationLoading ? t("agentIsLoading") : verificationPending ? t("verifyInputBlocked") : placeholder || t("typeYourMessage"),
20289
20387
  rows: 1,
20290
- disabled: csatVisible || isConversationLoading || isLoading || isVoiceSessionActive && voiceStatus !== "connected",
20388
+ disabled: csatVisible || isConversationLoading || isLoading || verificationPending || isVoiceSessionActive && voiceStatus !== "connected",
20291
20389
  dir: typedIsRtl ? "rtl" : "ltr",
20292
20390
  className: `w-full px-3 bg-transparent rounded-xl leading-normal ${isDark ? "text-gray-100" : "text-gray-900"} placeholder-gray-400 resize-none outline-none scrollbar-hide break-words`,
20293
20391
  style: {
@@ -20423,7 +20521,7 @@
20423
20521
  })
20424
20522
  }) : /*#__PURE__*/jsxRuntimeExports.jsx("button", {
20425
20523
  onClick: isVoiceSessionActive && onBidiSubmit && !hasReadyAttachment ? onBidiSubmit : sendWithAttachments,
20426
- disabled: csatVisible || isDisabled || isVoiceSessionActive && voiceStatus !== "connected",
20524
+ disabled: csatVisible || isDisabled || verificationPending || isVoiceSessionActive && voiceStatus !== "connected",
20427
20525
  className: `h-10 w-10 flex-shrink-0 rounded-xl transition-all duration-200 flex items-center justify-center shadow-md disabled:opacity-40 disabled:cursor-not-allowed disabled:shadow-none ${inputValue.trim() ? "scale-100" : "scale-95"}`,
20428
20526
  style: {
20429
20527
  backgroundColor: inputValue.trim() ? primaryColor : isDark ? "#374151" : "#e5e7eb",
@@ -21720,6 +21818,8 @@
21720
21818
  }
21721
21819
  }
21722
21820
 
21821
+ const VerificationContext = /*#__PURE__*/reactExports.createContext(null);
21822
+
21723
21823
  const DEFAULT_AGENT_BUBBLE_COLOR = "#ffffff";
21724
21824
  const DEFAULT_USER_MESSAGE_COLOR = "#f5f5f5";
21725
21825
  const DEFAULT_TEXT_COLOR = "#000000";
@@ -21871,6 +21971,35 @@
21871
21971
  const panelRef = reactExports.useRef(null);
21872
21972
  const t = reactExports.useMemo(() => createTranslator(defaultLanguage), [defaultLanguage]);
21873
21973
 
21974
+ // What the verify card (A2uiBlock "verification" fence) needs. The code is
21975
+ // posted to /support/identity, never through the chat send. Declared with
21976
+ // the other top-level hooks, ahead of the `if (!isOpen) return null;` below.
21977
+ // Cards still waiting for a code; while any is, the chat input is blocked.
21978
+ const [verificationPendingKeys, setVerificationPendingKeys] = reactExports.useState(() => new Set());
21979
+ const setVerificationPending = reactExports.useCallback((key, on) => {
21980
+ setVerificationPendingKeys(prev => {
21981
+ if (on === prev.has(key)) return prev;
21982
+ const next = new Set(prev);
21983
+ if (on) next.add(key);else next.delete(key);
21984
+ return next;
21985
+ });
21986
+ }, []);
21987
+ const verificationContextValue = reactExports.useMemo(() => apiBaseUrl && conversationId ? {
21988
+ t,
21989
+ setPending: setVerificationPending,
21990
+ start: payload => startVisitorVerification({
21991
+ ...payload,
21992
+ conversationId
21993
+ }, apiBaseUrl, getAuthToken),
21994
+ verify: payload => verifyVisitorCode({
21995
+ ...payload,
21996
+ conversationId
21997
+ }, apiBaseUrl, getAuthToken),
21998
+ status: () => visitorCodeStatus({
21999
+ conversationId
22000
+ }, apiBaseUrl, getAuthToken)
22001
+ } : null, [t, apiBaseUrl, conversationId, getAuthToken, setVerificationPending]);
22002
+
21874
22003
  // EV-2480: move focus into the dialog on open. This component only
21875
22004
  // mounts while isOpen is true (see the `if (!isOpen) return null;` below),
21876
22005
  // so a mount-only effect fires exactly once per open.
@@ -21908,8 +22037,13 @@
21908
22037
  // The structured answer rides on the send; the text is still the
21909
22038
  // message. A host override (onPromptSuggestionClick) keeps the text.
21910
22039
  const toolConfirmation = index && typeof index === "object" && index.toolConfirmation ? index.toolConfirmation : null;
22040
+ // The verify card's resume: the code was already checked by the
22041
+ // backend; this only tells the held tool to run.
22042
+ const verificationComplete = index && typeof index === "object" && index.verificationComplete ? index.verificationComplete : null;
21911
22043
  if (onPromptSuggestionClick) onPromptSuggestionClick(text);else if (toolConfirmation) onDirectSend?.(text, undefined, {
21912
22044
  toolConfirmation
22045
+ });else if (verificationComplete) onDirectSend?.(text, undefined, {
22046
+ verificationComplete
21913
22047
  });else onDirectSend?.(text);
21914
22048
  }, [onPromptSuggestionClick, onDirectSend, reportChipClick]);
21915
22049
 
@@ -22515,236 +22649,240 @@
22515
22649
  maxWidth: "92vw",
22516
22650
  maxHeight: "85vh"
22517
22651
  } : undefined;
22518
- return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22519
- dir: isRtlLanguage ? "rtl" : "ltr",
22520
- className: `relative flex-shrink-0 z-50 ${isMinimized ? "w-80 h-auto" : ""}`,
22521
- style: sizeStyle,
22522
- children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22523
- children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
22524
- onMouseDown: e => handleResizeStart("horizontal", e),
22525
- className: `absolute top-0 h-full w-1.5 cursor-ew-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorRight ? "left-0" : "right-0"}`,
22526
- "aria-hidden": true
22527
- }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22528
- onMouseDown: e => handleResizeStart("vertical", e),
22529
- className: `absolute left-0 w-full h-1.5 cursor-ns-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorBottom ? "top-0" : "bottom-0"}`,
22530
- "aria-hidden": true
22531
- })]
22532
- }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22533
- id: "chat-window-panel",
22534
- ref: panelRef,
22535
- role: "dialog",
22536
- "aria-modal": "true",
22537
- "aria-label": t("openChat"),
22538
- tabIndex: -1,
22539
- className: `relative focus:outline-none ${!widgetSize && !isMinimized ? "w-[380px]" : ""} ${!widgetSize && !isMinimized ? "h-[650px]" : ""} ${isMinimized ? "w-80 h-auto" : ""} ${widgetSize && !isMinimized ? "w-full h-full" : ""} max-w-[92vw] border rounded-2xl shadow-2xl bg-white border-gray-200 flex flex-col ${!isMinimized ? "max-h-[85vh]" : ""} overflow-hidden ${isDark ? "bg-gray-900 border-gray-700" : ""}`,
22540
- children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22541
- onMouseDown: e => handleResizeStart("corner", e),
22542
- "aria-hidden": "true",
22543
- className: `absolute w-4 h-4 ${anchorRight === anchorBottom ? "cursor-nwse-resize" : "cursor-nesw-resize"} text-gray-400 hover:text-blue-500 transition-colors z-[71] flex p-0.5 ${anchorBottom ? "top-0 items-start" : "bottom-0 items-end"} ${anchorRight ? "left-0 justify-start" : "right-0 justify-end"}`,
22544
- children: /*#__PURE__*/jsxRuntimeExports.jsx("svg", {
22545
- viewBox: "0 0 12 12",
22546
- className: `w-3 h-3 ${anchorBottom && anchorRight ? "rotate-180" : anchorBottom ? "-rotate-90" : anchorRight ? "rotate-90" : ""}`,
22547
- "aria-hidden": true,
22548
- children: /*#__PURE__*/jsxRuntimeExports.jsx("path", {
22549
- d: "M11 1 L1 11 M11 5 L5 11 M11 9 L9 11",
22550
- stroke: "currentColor",
22551
- strokeWidth: "1.5",
22552
- fill: "none",
22553
- strokeLinecap: "round"
22554
- })
22555
- })
22556
- }), /*#__PURE__*/jsxRuntimeExports.jsx(ChatHeader, {
22557
- conciergeName: conciergeName,
22558
- companyName: companyName,
22559
- companyLogo: companyLogo,
22560
- primaryColor: primaryColor,
22561
- isDark: isDark,
22562
- isMinimized: isMinimized,
22563
- textColor: resolvedTextColor,
22564
- fontFamily: fontFamily,
22565
- fontSize: fontSize,
22566
- onToggleTheme: onToggleTheme,
22567
- onMinimize: onMinimize,
22568
- onClose: handleCloseClick,
22569
- headerTextBold: headerTextBold,
22570
- headerTextItalic: headerTextItalic,
22571
- headerTextColor: headerTextColor,
22572
- headerFontFamily: headerFontFamily,
22573
- headerFontSize: headerFontSize,
22574
- subtitle: subtitle,
22575
- showStatus: showStatus,
22576
- statusMode: statusMode,
22577
- officeHours: officeHours,
22578
- onRefreshChat: onRefreshChat,
22579
- onCopyChat: onCopyChat,
22580
- defaultLanguage: defaultLanguage
22581
- }), !isMinimized && filterEnabled && !showInlineFilter && !(showResolveForm && !isConversationResolved) && !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(CategoryTabsBar, {
22582
- categories: filterCategories,
22583
- selectedCategoryId: widgetFilter?.category || null,
22584
- onSelect: handleSelectCategory,
22585
- isDark: isDark,
22586
- primaryColor: primaryColor,
22587
- fontFamily: fontFamily,
22588
- isRtl: isRtlLanguage,
22589
- defaultLanguage: defaultLanguage
22590
- }), !isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22652
+ return /*#__PURE__*/jsxRuntimeExports.jsx(VerificationContext.Provider, {
22653
+ value: verificationContextValue,
22654
+ children: /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22655
+ dir: isRtlLanguage ? "rtl" : "ltr",
22656
+ className: `relative flex-shrink-0 z-50 ${isMinimized ? "w-80 h-auto" : ""}`,
22657
+ style: sizeStyle,
22658
+ children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22591
22659
  children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
22592
- ref: messagesContainerRef,
22593
- role: "log",
22594
- "aria-live": "polite",
22595
- className: `chat-messages flex-1 overflow-y-auto px-3 py-4 space-y-4 ${isDark ? "bg-gray-900" : "bg-gradient-to-b from-gray-50/50 to-white"} break-words`,
22596
- children: showResolveForm && !isConversationResolved ? renderFeedbackForm() : onboardingActive && !onboardingCompleted && onOnboardingFormSubmit ? /*#__PURE__*/jsxRuntimeExports.jsx(OnboardingForm, {
22597
- questions: onboardingQuestions,
22598
- onPromptSuggestionClick: stableOnPromptSuggestionClick,
22599
- collapsiblePrompt: collectionPrompt,
22600
- onSubmit: onOnboardingFormSubmit,
22601
- primaryColor: primaryColor,
22602
- isRtl: isRtlLanguage,
22603
- isDark: isDark,
22604
- defaultLanguage: defaultLanguage,
22605
- fontFamily: fontFamily
22606
- }) : /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22607
- children: [sessionExpiringSoon && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22608
- role: "status",
22609
- className: `mx-3 mt-1 mb-2 rounded-lg px-3 py-2 text-xs font-medium ${isDark ? 'bg-amber-900/40 text-amber-200 border border-amber-700/50' : 'bg-amber-50 text-amber-800 border border-amber-200'}`,
22610
- children: t("sessionExpiringSoon")
22611
- }), /*#__PURE__*/jsxRuntimeExports.jsx(MessageList, {
22612
- messages: messages,
22613
- liveJoined: liveJoined,
22614
- isDark: isDark,
22660
+ onMouseDown: e => handleResizeStart("horizontal", e),
22661
+ className: `absolute top-0 h-full w-1.5 cursor-ew-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorRight ? "left-0" : "right-0"}`,
22662
+ "aria-hidden": true
22663
+ }), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22664
+ onMouseDown: e => handleResizeStart("vertical", e),
22665
+ className: `absolute left-0 w-full h-1.5 cursor-ns-resize hover:bg-blue-500/20 transition-colors z-[70] ${anchorBottom ? "top-0" : "bottom-0"}`,
22666
+ "aria-hidden": true
22667
+ })]
22668
+ }), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
22669
+ id: "chat-window-panel",
22670
+ ref: panelRef,
22671
+ role: "dialog",
22672
+ "aria-modal": "true",
22673
+ "aria-label": t("openChat"),
22674
+ tabIndex: -1,
22675
+ className: `relative focus:outline-none ${!widgetSize && !isMinimized ? "w-[380px]" : ""} ${!widgetSize && !isMinimized ? "h-[650px]" : ""} ${isMinimized ? "w-80 h-auto" : ""} ${widgetSize && !isMinimized ? "w-full h-full" : ""} max-w-[92vw] border rounded-2xl shadow-2xl bg-white border-gray-200 flex flex-col ${!isMinimized ? "max-h-[85vh]" : ""} overflow-hidden ${isDark ? "bg-gray-900 border-gray-700" : ""}`,
22676
+ children: [!isMinimized && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22677
+ onMouseDown: e => handleResizeStart("corner", e),
22678
+ "aria-hidden": "true",
22679
+ className: `absolute w-4 h-4 ${anchorRight === anchorBottom ? "cursor-nwse-resize" : "cursor-nesw-resize"} text-gray-400 hover:text-blue-500 transition-colors z-[71] flex p-0.5 ${anchorBottom ? "top-0 items-start" : "bottom-0 items-end"} ${anchorRight ? "left-0 justify-start" : "right-0 justify-end"}`,
22680
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("svg", {
22681
+ viewBox: "0 0 12 12",
22682
+ className: `w-3 h-3 ${anchorBottom && anchorRight ? "rotate-180" : anchorBottom ? "-rotate-90" : anchorRight ? "rotate-90" : ""}`,
22683
+ "aria-hidden": true,
22684
+ children: /*#__PURE__*/jsxRuntimeExports.jsx("path", {
22685
+ d: "M11 1 L1 11 M11 5 L5 11 M11 9 L9 11",
22686
+ stroke: "currentColor",
22687
+ strokeWidth: "1.5",
22688
+ fill: "none",
22689
+ strokeLinecap: "round"
22690
+ })
22691
+ })
22692
+ }), /*#__PURE__*/jsxRuntimeExports.jsx(ChatHeader, {
22693
+ conciergeName: conciergeName,
22694
+ companyName: companyName,
22695
+ companyLogo: companyLogo,
22696
+ primaryColor: primaryColor,
22697
+ isDark: isDark,
22698
+ isMinimized: isMinimized,
22699
+ textColor: resolvedTextColor,
22700
+ fontFamily: fontFamily,
22701
+ fontSize: fontSize,
22702
+ onToggleTheme: onToggleTheme,
22703
+ onMinimize: onMinimize,
22704
+ onClose: handleCloseClick,
22705
+ headerTextBold: headerTextBold,
22706
+ headerTextItalic: headerTextItalic,
22707
+ headerTextColor: headerTextColor,
22708
+ headerFontFamily: headerFontFamily,
22709
+ headerFontSize: headerFontSize,
22710
+ subtitle: subtitle,
22711
+ showStatus: showStatus,
22712
+ statusMode: statusMode,
22713
+ officeHours: officeHours,
22714
+ onRefreshChat: onRefreshChat,
22715
+ onCopyChat: onCopyChat,
22716
+ defaultLanguage: defaultLanguage
22717
+ }), !isMinimized && filterEnabled && !showInlineFilter && !(showResolveForm && !isConversationResolved) && !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(CategoryTabsBar, {
22718
+ categories: filterCategories,
22719
+ selectedCategoryId: widgetFilter?.category || null,
22720
+ onSelect: handleSelectCategory,
22721
+ isDark: isDark,
22722
+ primaryColor: primaryColor,
22723
+ fontFamily: fontFamily,
22724
+ isRtl: isRtlLanguage,
22725
+ defaultLanguage: defaultLanguage
22726
+ }), !isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22727
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
22728
+ ref: messagesContainerRef,
22729
+ role: "log",
22730
+ "aria-live": "polite",
22731
+ className: `chat-messages flex-1 overflow-y-auto px-3 py-4 space-y-4 ${isDark ? "bg-gray-900" : "bg-gradient-to-b from-gray-50/50 to-white"} break-words`,
22732
+ children: showResolveForm && !isConversationResolved ? renderFeedbackForm() : onboardingActive && !onboardingCompleted && onOnboardingFormSubmit ? /*#__PURE__*/jsxRuntimeExports.jsx(OnboardingForm, {
22733
+ questions: onboardingQuestions,
22734
+ onPromptSuggestionClick: stableOnPromptSuggestionClick,
22735
+ collapsiblePrompt: collectionPrompt,
22736
+ onSubmit: onOnboardingFormSubmit,
22615
22737
  primaryColor: primaryColor,
22616
- isLoading: isLoading,
22617
- agentMessageBubbleColor: agentMessageBubbleColor,
22618
- userMessageBoxColor: userMessageBoxColor,
22619
- textColor: textColor,
22620
- assistantTextColor: assistantTextColor,
22621
- userTextColor: userTextColor,
22622
- fontFamily: fontFamily,
22623
- agentMessageBubbleFontFamily: agentMessageBubbleFontFamily,
22624
- agentMessageBubbleFontSize: agentMessageBubbleFontSize,
22625
- userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22626
- userMessageBubbleFontSize: userMessageBubbleFontSize,
22627
- fontSize: fontSize,
22628
- formatTime: formatTime,
22629
22738
  isRtl: isRtlLanguage,
22739
+ isDark: isDark,
22630
22740
  defaultLanguage: defaultLanguage,
22631
- quickQuestions: quickQuestions,
22632
- shouldShowQuickQuestions: shouldShowQuickQuestions,
22633
- onQuickQuestion: onQuickQuestion ?? onDirectSend,
22634
- quickQuestionsLayout: quickQuestionsLayout,
22635
- onDecision: onDecision,
22636
- disclaimerEnabled: disclaimerEnabled,
22637
- disclaimerText: disclaimerText,
22638
- disclaimerPosition: disclaimerPosition,
22639
- disclaimerLinkUrl: disclaimerLinkUrl,
22640
- disclaimerLinkLabel: disclaimerLinkLabel,
22641
- resolvedAgentBubbleColor: resolvedAgentBubbleColor,
22642
- resolvedUserMessageColor: resolvedUserMessageColor,
22643
- resolvedTextColor: resolvedTextColor,
22644
- isVoiceSessionActive: isVoiceSessionActive,
22645
- voiceStatus: voiceStatus,
22646
- messagesContainerRef: messagesContainerRef,
22647
- companyLogo: companyLogo,
22648
- chatbotAvatarEnabled: chatbotAvatarEnabled,
22649
- chatbotAvatar: chatbotAvatar,
22650
- conciergeName: conciergeName,
22651
- companyName: companyName,
22652
- apiBaseUrl: apiBaseUrl,
22653
- getAuthToken: getAuthToken,
22654
- onPromptSuggestionClick: stableOnPromptSuggestionClick,
22655
- conversationResetKey: conversationId,
22656
- allowFeedback: allowFeedback,
22657
- provideCitations: provideCitations,
22658
- onFeedback: onFeedback,
22659
- onRetryMessage: onRetryMessage,
22660
- headerTextColor: headerTextColor,
22661
- beforePromptsSlot: showInlineFilter ? /*#__PURE__*/jsxRuntimeExports.jsx(CategoryFilterInline, {
22662
- categories: filterCategories,
22663
- selectedCategoryId: widgetFilter?.category || null,
22664
- onSelect: handleSelectCategory,
22741
+ fontFamily: fontFamily
22742
+ }) : /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
22743
+ children: [sessionExpiringSoon && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22744
+ role: "status",
22745
+ className: `mx-3 mt-1 mb-2 rounded-lg px-3 py-2 text-xs font-medium ${isDark ? 'bg-amber-900/40 text-amber-200 border border-amber-700/50' : 'bg-amber-50 text-amber-800 border border-amber-200'}`,
22746
+ children: t("sessionExpiringSoon")
22747
+ }), /*#__PURE__*/jsxRuntimeExports.jsx(MessageList, {
22748
+ messages: messages,
22749
+ liveJoined: liveJoined,
22665
22750
  isDark: isDark,
22666
22751
  primaryColor: primaryColor,
22752
+ isLoading: isLoading,
22753
+ agentMessageBubbleColor: agentMessageBubbleColor,
22754
+ userMessageBoxColor: userMessageBoxColor,
22755
+ textColor: textColor,
22756
+ assistantTextColor: assistantTextColor,
22757
+ userTextColor: userTextColor,
22667
22758
  fontFamily: fontFamily,
22759
+ agentMessageBubbleFontFamily: agentMessageBubbleFontFamily,
22760
+ agentMessageBubbleFontSize: agentMessageBubbleFontSize,
22761
+ userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22762
+ userMessageBubbleFontSize: userMessageBubbleFontSize,
22668
22763
  fontSize: fontSize,
22764
+ formatTime: formatTime,
22669
22765
  isRtl: isRtlLanguage,
22670
- label: t("chooseTopicLabel"),
22671
- regionLabel: t("categoryFilter")
22672
- }) : null,
22673
- quickQuestionsHeadingLabel: filterEnabled ? t("quickQuestionsHeadingLabel") : undefined
22674
- }), (showCsat && csatEnabled || csatRequest) && !csatSubmitted && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22675
- className: "",
22676
- "data-testid": "widget-csat-card",
22677
- children: /*#__PURE__*/jsxRuntimeExports.jsx(CSATWidget, {
22678
- format: normalizeCsatFormat(csatRequest?.format || csatFormat),
22679
- prompt: csatRequest?.prompt || csatPrompt || t("howWasYourExperience"),
22680
- onRating: handleCsatRating,
22681
- disabled: false,
22682
- isDark: isDark,
22683
- primaryColor: primaryColor,
22684
- defaultLanguage: defaultLanguage
22685
- })
22686
- })]
22687
- })
22688
- }), !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(ChatInput, {
22689
- onSynthesizeAssistantMessage: onSynthesizeAssistantMessage,
22690
- onStopGeneration: onStopGeneration,
22691
- inputValue: inputValue,
22692
- setInputValue: setInputValue,
22693
- onSend: onSend,
22694
- isDark: isDark,
22695
- primaryColor: primaryColor,
22696
- isOpen: isOpen,
22697
- isMinimized: isMinimized,
22698
- isLoading: isLoading,
22699
- isConversationLoading: isConversationLoading,
22700
- placeholder: placeholder,
22701
- textColor: resolvedTextColor,
22702
- fontFamily: fontFamily,
22703
- userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22704
- userMessageBubbleFontSize: userMessageBubbleFontSize,
22705
- fontSize: fontSize,
22706
- isRtl: isRtlLanguage,
22707
- csatVisible: showCsat && csatEnabled && !csatSubmitted || isCsatEnabled && (showResolveForm || isConversationResolved),
22708
- enableVoiceInteraction: enableVoiceInteraction,
22709
- isVoiceSessionActive: isVoiceSessionActive,
22710
- voiceStatus: voiceStatus,
22711
- voiceError: voiceError,
22712
- onVoiceToggle: onVoiceToggle,
22713
- onBidiSubmit: onBidiSubmit,
22714
- disclaimerEnabled: disclaimerEnabled,
22715
- disclaimerText: disclaimerText,
22716
- disclaimerPosition: disclaimerPosition,
22717
- disclaimerLinkUrl: disclaimerLinkUrl,
22718
- disclaimerLinkLabel: disclaimerLinkLabel,
22719
- showPoweredBy: showPoweredBy,
22720
- defaultLanguage: defaultLanguage,
22721
- onboardingQuestions: onboardingQuestions,
22722
- onboardingActive: onboardingActive,
22723
- onboardingCompleted: onboardingCompleted,
22724
- onboardingEnabled: onboardingEnabled,
22725
- userMessageBoxColor: userMessageBoxColor,
22726
- resolvedUserMessageColor: resolvedUserMessageColor,
22727
- userTextColor: userTextColor,
22728
- promptSuggestions: showResolveForm || isConversationResolved || autoPromptEnabled === false || isLoading ? [] : stablePromptSuggestions,
22729
- onPromptSuggestionClick: stableOnPromptSuggestionClick,
22730
- autoPromptQuestionDisplay: autoPromptQuestionDisplay,
22731
- tagSelectorNode: null,
22732
- showResolveButton: isCsatEnabled && hasUserMessages && !isConversationResolved && !showResolveForm && !showCsat && !shouldHideResolveForOnboarding,
22733
- onResolve: () => {
22734
- if (!isCsatEnabled) return;
22735
- setShowResolveForm(true);
22736
- }
22737
- // Attachments (RAG-attach-1) - paperclip stays hidden
22738
- // unless the operator explicitly opted in via
22739
- // MasterAgent.config.chatFeatures.
22740
- ,
22741
- chatFeatures: chatFeatures,
22742
- apiEndpoint: apiBaseUrl,
22743
- organizationId: organizationId,
22744
- conversationId: conversationId
22766
+ defaultLanguage: defaultLanguage,
22767
+ quickQuestions: quickQuestions,
22768
+ shouldShowQuickQuestions: shouldShowQuickQuestions,
22769
+ onQuickQuestion: onQuickQuestion ?? onDirectSend,
22770
+ quickQuestionsLayout: quickQuestionsLayout,
22771
+ onDecision: onDecision,
22772
+ disclaimerEnabled: disclaimerEnabled,
22773
+ disclaimerText: disclaimerText,
22774
+ disclaimerPosition: disclaimerPosition,
22775
+ disclaimerLinkUrl: disclaimerLinkUrl,
22776
+ disclaimerLinkLabel: disclaimerLinkLabel,
22777
+ resolvedAgentBubbleColor: resolvedAgentBubbleColor,
22778
+ resolvedUserMessageColor: resolvedUserMessageColor,
22779
+ resolvedTextColor: resolvedTextColor,
22780
+ isVoiceSessionActive: isVoiceSessionActive,
22781
+ voiceStatus: voiceStatus,
22782
+ messagesContainerRef: messagesContainerRef,
22783
+ companyLogo: companyLogo,
22784
+ chatbotAvatarEnabled: chatbotAvatarEnabled,
22785
+ chatbotAvatar: chatbotAvatar,
22786
+ conciergeName: conciergeName,
22787
+ companyName: companyName,
22788
+ apiBaseUrl: apiBaseUrl,
22789
+ getAuthToken: getAuthToken,
22790
+ onPromptSuggestionClick: stableOnPromptSuggestionClick,
22791
+ conversationResetKey: conversationId,
22792
+ allowFeedback: allowFeedback,
22793
+ provideCitations: provideCitations,
22794
+ onFeedback: onFeedback,
22795
+ onRetryMessage: onRetryMessage,
22796
+ headerTextColor: headerTextColor,
22797
+ beforePromptsSlot: showInlineFilter ? /*#__PURE__*/jsxRuntimeExports.jsx(CategoryFilterInline, {
22798
+ categories: filterCategories,
22799
+ selectedCategoryId: widgetFilter?.category || null,
22800
+ onSelect: handleSelectCategory,
22801
+ isDark: isDark,
22802
+ primaryColor: primaryColor,
22803
+ fontFamily: fontFamily,
22804
+ fontSize: fontSize,
22805
+ isRtl: isRtlLanguage,
22806
+ label: t("chooseTopicLabel"),
22807
+ regionLabel: t("categoryFilter")
22808
+ }) : null,
22809
+ quickQuestionsHeadingLabel: filterEnabled ? t("quickQuestionsHeadingLabel") : undefined
22810
+ }), (showCsat && csatEnabled || csatRequest) && !csatSubmitted && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
22811
+ className: "",
22812
+ "data-testid": "widget-csat-card",
22813
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(CSATWidget, {
22814
+ format: normalizeCsatFormat(csatRequest?.format || csatFormat),
22815
+ prompt: csatRequest?.prompt || csatPrompt || t("howWasYourExperience"),
22816
+ onRating: handleCsatRating,
22817
+ disabled: false,
22818
+ isDark: isDark,
22819
+ primaryColor: primaryColor,
22820
+ defaultLanguage: defaultLanguage
22821
+ })
22822
+ })]
22823
+ })
22824
+ }), !(onboardingActive && !onboardingCompleted) && /*#__PURE__*/jsxRuntimeExports.jsx(ChatInput, {
22825
+ onSynthesizeAssistantMessage: onSynthesizeAssistantMessage,
22826
+ onStopGeneration: onStopGeneration,
22827
+ inputValue: inputValue,
22828
+ setInputValue: setInputValue,
22829
+ onSend: onSend,
22830
+ isDark: isDark,
22831
+ primaryColor: primaryColor,
22832
+ isOpen: isOpen,
22833
+ isMinimized: isMinimized,
22834
+ isLoading: isLoading,
22835
+ isConversationLoading: isConversationLoading,
22836
+ verificationPending: verificationPendingKeys.size > 0,
22837
+ placeholder: placeholder,
22838
+ textColor: resolvedTextColor,
22839
+ fontFamily: fontFamily,
22840
+ userMessageBubbleFontFamily: userMessageBubbleFontFamily,
22841
+ userMessageBubbleFontSize: userMessageBubbleFontSize,
22842
+ fontSize: fontSize,
22843
+ isRtl: isRtlLanguage,
22844
+ csatVisible: showCsat && csatEnabled && !csatSubmitted || isCsatEnabled && (showResolveForm || isConversationResolved),
22845
+ enableVoiceInteraction: enableVoiceInteraction,
22846
+ isVoiceSessionActive: isVoiceSessionActive,
22847
+ voiceStatus: voiceStatus,
22848
+ voiceError: voiceError,
22849
+ onVoiceToggle: onVoiceToggle,
22850
+ onBidiSubmit: onBidiSubmit,
22851
+ disclaimerEnabled: disclaimerEnabled,
22852
+ disclaimerText: disclaimerText,
22853
+ disclaimerPosition: disclaimerPosition,
22854
+ disclaimerLinkUrl: disclaimerLinkUrl,
22855
+ disclaimerLinkLabel: disclaimerLinkLabel,
22856
+ showPoweredBy: showPoweredBy,
22857
+ defaultLanguage: defaultLanguage,
22858
+ onboardingQuestions: onboardingQuestions,
22859
+ onboardingActive: onboardingActive,
22860
+ onboardingCompleted: onboardingCompleted,
22861
+ onboardingEnabled: onboardingEnabled,
22862
+ userMessageBoxColor: userMessageBoxColor,
22863
+ resolvedUserMessageColor: resolvedUserMessageColor,
22864
+ userTextColor: userTextColor,
22865
+ promptSuggestions: showResolveForm || isConversationResolved || autoPromptEnabled === false || isLoading ? [] : stablePromptSuggestions,
22866
+ onPromptSuggestionClick: stableOnPromptSuggestionClick,
22867
+ autoPromptQuestionDisplay: autoPromptQuestionDisplay,
22868
+ tagSelectorNode: null,
22869
+ showResolveButton: isCsatEnabled && hasUserMessages && !isConversationResolved && !showResolveForm && !showCsat && !shouldHideResolveForOnboarding,
22870
+ onResolve: () => {
22871
+ if (!isCsatEnabled) return;
22872
+ setShowResolveForm(true);
22873
+ }
22874
+ // Attachments (RAG-attach-1) - paperclip stays hidden
22875
+ // unless the operator explicitly opted in via
22876
+ // MasterAgent.config.chatFeatures.
22877
+ ,
22878
+ chatFeatures: chatFeatures,
22879
+ apiEndpoint: apiBaseUrl,
22880
+ organizationId: organizationId,
22881
+ conversationId: conversationId
22882
+ })]
22745
22883
  })]
22746
22884
  })]
22747
- })]
22885
+ })
22748
22886
  });
22749
22887
  };
22750
22888
 
@@ -23063,7 +23201,7 @@
23063
23201
  * value by its own test (that constant sat at 0.1.113 while this package was
23064
23202
  * at 0.2.2 precisely because nothing enforced it - EV-2431).
23065
23203
  */
23066
- const WIDGET_VERSION = '0.2.34';
23204
+ const WIDGET_VERSION = '0.2.36';
23067
23205
 
23068
23206
  /**
23069
23207
  * API utility functions