UNPKG

@iotauz/ai-chat

Version:

A customizable React chatbot component for IOTA SDK

983 lines (975 loc) 63.8 kB
import * as React from 'react'; import React__default, { useState, useRef, useEffect, useCallback } from 'react'; import 'clsx'; import 'tailwind-merge'; import { X, MessageCircle, Send } from 'lucide-react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { InputMask } from '@react-input/mask'; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols) for (var prop of __getOwnPropSymbols(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) target[prop] = source[prop]; } return target; }; var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; function formatDate(date, translations2) { const day = date.getDate(); const month = translations2.months[date.getMonth()]; const year = date.getFullYear(); return `${month} ${day}, ${year}`; } function CallbackModal({ isOpen, onClose, onSubmit, translations: translations2 }) { const [phoneNumber, setPhoneNumber] = useState(""); const [consentChecked, setConsentChecked] = useState(false); if (!isOpen) { return null; } const handleSubmit = () => { if (phoneNumber.trim() && consentChecked) { onSubmit(phoneNumber); onClose(); } }; return /* @__PURE__ */ React__default.createElement("div", { className: "fixed inset-0 bg-black/50 flex items-center justify-center z-50" }, /* @__PURE__ */ React__default.createElement("div", { className: "bg-white rounded-3xl w-full max-w-md mx-4 overflow-hidden" }, /* @__PURE__ */ React__default.createElement("div", { className: "p-4 flex justify-between items-center" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-gray-500 text-sm" }, "Modal"), /* @__PURE__ */ React__default.createElement( "button", { onClick: onClose, className: "w-8 h-8 flex items-center justify-center rounded-full border border-gray-300" }, /* @__PURE__ */ React__default.createElement(X, { size: 16 }) )), /* @__PURE__ */ React__default.createElement("div", { className: "p-6 pt-0" }, /* @__PURE__ */ React__default.createElement("h2", { className: "text-2xl font-medium text-[#0a223e] mb-2" }, translations2.callbackModalTitle), /* @__PURE__ */ React__default.createElement("p", { className: "text-[#8b98a5] mb-6" }, translations2.callbackModalSubtitle), /* @__PURE__ */ React__default.createElement("div", { className: "mb-2 text-[#8b98a5] text-sm" }, translations2.callbackPhoneInputLabel), /* @__PURE__ */ React__default.createElement("div", { className: "relative mb-4" }, /* @__PURE__ */ React__default.createElement( "input", { type: "text", className: "w-full p-3 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 focus:ring-[#2e67b4]", placeholder: translations2.phoneInputPlaceholder, value: phoneNumber, onChange: (e) => setPhoneNumber(e.target.value) } ), /* @__PURE__ */ React__default.createElement("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2 bg-[#2e67b4] text-white w-6 h-6 rounded-full flex items-center justify-center" }, /* @__PURE__ */ React__default.createElement("span", { className: "text-xs" }, "B"))), /* @__PURE__ */ React__default.createElement("p", { className: "text-[#2e67b4] text-sm mb-4" }, translations2.dataPrivacyMessage), /* @__PURE__ */ React__default.createElement("div", { className: "flex items-start mb-6" }, /* @__PURE__ */ React__default.createElement( "div", { className: `w-6 h-6 flex-shrink-0 rounded border ${consentChecked ? "bg-[#2e67b4] border-[#2e67b4] flex items-center justify-center" : "border-gray-300"} mr-2 cursor-pointer`, onClick: () => setConsentChecked(!consentChecked) }, consentChecked && /* @__PURE__ */ React__default.createElement("span", { className: "text-white text-xs" }, "\u2713") ), /* @__PURE__ */ React__default.createElement("span", { className: "text-[#0a223e]" }, translations2.dataProcessingConsent)), /* @__PURE__ */ React__default.createElement("div", { className: "flex gap-4" }, /* @__PURE__ */ React__default.createElement("button", { onClick: onClose, className: "flex-1 py-3 bg-[#e4e9ee] text-[#0a223e] rounded-lg" }, translations2.backButton), /* @__PURE__ */ React__default.createElement( "button", { onClick: handleSubmit, disabled: !phoneNumber.trim() || !consentChecked, className: `flex-1 py-3 rounded-lg ${phoneNumber.trim() && consentChecked ? "bg-[#2e67b4] text-white" : "bg-[#e4e9ee] text-[#bdc8d2]"}` }, translations2.requestCallButton ))))); } function MessageLoading() { return /* @__PURE__ */ React__default.createElement( "svg", { width: "24", height: "24", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", className: "text-foreground" }, /* @__PURE__ */ React__default.createElement("circle", { cx: "4", cy: "12", r: "2", fill: "currentColor" }, /* @__PURE__ */ React__default.createElement( "animate", { id: "spinner_qFRN", begin: "0;spinner_OcgL.end+0.25s", attributeName: "cy", calcMode: "spline", dur: "0.6s", values: "12;6;12", keySplines: ".33,.66,.66,1;.33,0,.66,.33" } )), /* @__PURE__ */ React__default.createElement("circle", { cx: "12", cy: "12", r: "2", fill: "currentColor" }, /* @__PURE__ */ React__default.createElement( "animate", { begin: "spinner_qFRN.begin+0.1s", attributeName: "cy", calcMode: "spline", dur: "0.6s", values: "12;6;12", keySplines: ".33,.66,.66,1;.33,0,.66,.33" } )), /* @__PURE__ */ React__default.createElement("circle", { cx: "20", cy: "12", r: "2", fill: "currentColor" }, /* @__PURE__ */ React__default.createElement( "animate", { id: "spinner_OcgL", begin: "spinner_qFRN.begin+0.2s", attributeName: "cy", calcMode: "spline", dur: "0.6s", values: "12;6;12", keySplines: ".33,.66,.66,1;.33,0,.66,.33" } )) ); } // components/typing-indicator.tsx function TypingIndicator({ translations: translations2, botTitle }) { return /* @__PURE__ */ React__default.createElement("div", { className: "max-w-[80%] bg-white rounded-lg p-4 shadow-sm" }, /* @__PURE__ */ React__default.createElement("div", { className: "text-[#2e67b4] font-medium mb-2" }, botTitle || translations2.chatbotTitle), /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React__default.createElement(MessageLoading, null))); } function QuickReplyButtons({ translations: translations2, isTyping, onQuickReply, faqItems }) { const buttonClasses = "flex-1 px-4 py-3 text-[#0a223e] bg-white border border-gray-300 rounded-full text-sm whitespace-normal text-center min-h-[40px] flex items-center justify-center"; const defaultFAQs = [ { id: "extend-policy", question: translations2.extendPolicyQuestion }, { id: "find-contract", question: translations2.findContractNumberQuestion }, { id: "submit-claim", question: translations2.submitClaimQuestion } ]; const faqs = faqItems || defaultFAQs; return /* @__PURE__ */ React__default.createElement("div", { className: "flex flex-wrap gap-2 mb-4" }, faqs.length > 0 && faqs.slice(0, 2).map((faq) => /* @__PURE__ */ React__default.createElement("button", { key: faq.id, className: buttonClasses, onClick: () => onQuickReply(faq.question), disabled: isTyping }, faq.question)), faqs.length > 2 && /* @__PURE__ */ React__default.createElement( "button", { className: "w-full px-4 py-3 text-[#0a223e] bg-white border border-gray-300 rounded-full text-sm whitespace-normal text-center min-h-[40px] flex items-center justify-center mt-2", onClick: () => onQuickReply(faqs[2].question), disabled: isTyping }, faqs[2].question )); } // lib/errors.ts var ApiError = class _ApiError extends Error { constructor(message, code, details) { super(message); this.name = "ApiError"; this.code = code; this.details = details; Object.setPrototypeOf(this, _ApiError.prototype); } /** * Check if this error has a specific code */ hasCode(code) { return this.code === code; } /** * Check if this error has one of the specified codes */ hasOneOfCodes(codes) { return codes.includes(this.code); } }; // lib/api-service.ts var ChatApiService = class { constructor() { this.apiEndpoint = ""; } setApiEndpoint(endpoint) { this.apiEndpoint = endpoint; } createThread(data) { return __async(this, null, function* () { const response = yield fetch(`${this.apiEndpoint}/messages`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); if (!response.ok) { const errorData = yield response.json().catch(() => null); throw new ApiError( (errorData == null ? void 0 : errorData.message) || `API error: ${response.status}`, (errorData == null ? void 0 : errorData.code) || "UNKNOWN_ERROR", errorData || { status: response.status } ); } return yield response.json(); }); } // Get all messages for a thread getMessages(threadId) { return __async(this, null, function* () { const response = yield fetch(`${this.apiEndpoint}/messages/${threadId}`, { method: "GET", headers: { "Content-Type": "application/json" } }); if (!response.ok) { const errorData = yield response.json().catch(() => null); throw new ApiError( (errorData == null ? void 0 : errorData.message) || `API error: ${response.status}`, (errorData == null ? void 0 : errorData.code) || "UNKNOWN_ERROR", errorData || { status: response.status } ); } return yield response.json(); }); } // Add a new message to an existing thread addMessage(threadId, data) { return __async(this, null, function* () { const response = yield fetch(`${this.apiEndpoint}/messages/${threadId}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); if (!response.ok) { const errorData = yield response.json().catch(() => null); throw new ApiError( (errorData == null ? void 0 : errorData.message) || `API error: ${response.status}`, (errorData == null ? void 0 : errorData.code) || "UNKNOWN_ERROR", errorData || { status: response.status } ); } return yield response.json(); }); } }; var chatApi = new ChatApiService(); // lib/translations.ts var ru = { // Header chatbotTitle: "Ai chat bot", chatbotSubtitle: "\u041D\u0430\u0448 AI-\u0431\u043E\u0442 \u0433\u043E\u0442\u043E\u0432 \u043F\u043E\u043C\u043E\u0447\u044C \u0432\u0430\u043C \u043A\u0440\u0443\u0433\u043B\u043E\u0441\u0443\u0442\u043E\u0447\u043D\u043E", // Welcome message welcomeGreeting: "\u041F\u0440\u0438\u0432\u0435\u0442! \u{1F44B}", welcomeMessage: "\u042F \u0410\u043B\u0438, \u0432\u0430\u0448 \u0432\u0438\u0440\u0442\u0443\u0430\u043B\u044C\u043D\u044B\u0439 \u043F\u043E\u043C\u043E\u0449\u043D\u0438\u043A \u043E\u0442 Euroasia Insurance. \u0413\u043E\u0442\u043E\u0432 \u043F\u043E\u043C\u043E\u0447\u044C \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u0442\u044C\u0441\u044F \u0432 \u043C\u0438\u0440\u0435 \u0441\u0442\u0440\u0430\u0445\u043E\u0432\u0430\u043D\u0438\u044F, \u043F\u043E\u0434\u043E\u0431\u0440\u0430\u0442\u044C \u043D\u0443\u0436\u043D\u044B\u0439 \u043F\u043E\u043B\u0438\u0441 \u0438\u043B\u0438 \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u043D\u0430 \u043B\u044E\u0431\u044B\u0435 \u0432\u0430\u0448\u0438 \u0432\u043E\u043F\u0440\u043E\u0441\u044B. \u0421\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439\u0442\u0435, \u043D\u0435 \u0441\u0442\u0435\u0441\u043D\u044F\u0439\u0442\u0435\u0441\u044C! \u0427\u0435\u043C \u043C\u043E\u0433\u0443 \u0431\u044B\u0442\u044C \u043F\u043E\u043B\u0435\u0437\u0435\u043D \u0441\u0435\u0433\u043E\u0434\u043D\u044F?", phoneRequestMessage: "\u0427\u0442\u043E\u0431\u044B \u043D\u0430\u0447\u0430\u0442\u044C, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0441\u0432\u043E\u0439 \u043D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u2014 \u043C\u044B \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C \u0435\u0433\u043E \u0434\u043B\u044F \u0441\u0432\u044F\u0437\u0438 \u0438 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u044F \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u043E\u0431\u0440\u0430\u0449\u0435\u043D\u0438\u0439.", // Input placeholders phoneInputPlaceholder: "+ 998 (__) ___ __ __", phoneInputLabel: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448 \u043D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430", messageInputPlaceholder: "\u0412\u0430\u0448 \u0437\u0430\u043F\u0440\u043E\u0441", // Buttons sendButton: "\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C", callbackRequestButton: "\u0417\u0430\u043F\u0440\u043E\u0441 \u043E\u0431\u0440\u0430\u0442\u043D\u043E\u0433\u043E \u0437\u0432\u043E\u043D\u043A\u0430", // Quick replies extendPolicyQuestion: "\u041A\u0430\u043A \u043F\u0440\u043E\u0434\u043B\u0438\u0442\u044C \u043F\u043E\u043B\u0438\u0441?", findContractNumberQuestion: "\u0413\u0434\u0435 \u043D\u0430\u0439\u0442\u0438 \u043D\u043E\u043C\u0435\u0440 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0430?", submitClaimQuestion: "\u041A\u0430\u043A \u043F\u043E\u0434\u0430\u0442\u044C \u0437\u0430\u044F\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u0430 \u0441\u0442\u0440\u0430\u0445\u043E\u0432\u043E\u0439 \u0441\u043B\u0443\u0447\u0430\u0439?", // Callback modal callbackModalTitle: "\u0417\u0430\u043A\u0430\u0436\u0438\u0442\u0435 \u043E\u0431\u0440\u0430\u0442\u043D\u044B\u0439 \u0437\u0432\u043E\u043D\u043E\u043A", callbackModalSubtitle: "\u041E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u0441\u0432\u043E\u0439 \u043D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430, \u0438 \u043D\u0430\u0448 \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u0438\u0441\u0442 \u0441\u0432\u044F\u0436\u0435\u0442\u0441\u044F \u0441 \u0432\u0430\u043C\u0438 \u0432 \u0431\u043B\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u0432\u0440\u0435\u043C\u044F", callbackPhoneInputLabel: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430", dataPrivacyMessage: "\u041C\u044B \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u0451\u043C \u0432\u0430\u0448\u0438 \u0434\u0430\u043D\u043D\u044B\u0435 \u0442\u0440\u0435\u0442\u044C\u0438\u043C \u043B\u0438\u0446\u0430\u043C", dataProcessingConsent: "\u0421\u043E\u0433\u043B\u0430\u0441\u0435\u043D(\u0430) \u0441 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u043E\u0439 \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u044C\u043D\u044B\u0445 \u0434\u0430\u043D\u043D\u044B\u0445", backButton: "\u041D\u0430\u0437\u0430\u0434", requestCallButton: "\u0417\u0430\u043A\u0430\u0437\u0430\u0442\u044C \u0437\u0432\u043E\u043D\u043E\u043A", // Messages callbackConfirmation: "\u0421\u043F\u0430\u0441\u0438\u0431\u043E \u0437\u0430 \u0437\u0430\u043F\u0440\u043E\u0441! \u041D\u0430\u0448 \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u0438\u0441\u0442 \u0441\u0432\u044F\u0436\u0435\u0442\u0441\u044F \u0441 \u0432\u0430\u043C\u0438 \u043F\u043E \u043D\u043E\u043C\u0435\u0440\u0443 {phone} \u0432 \u0431\u043B\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u0432\u0440\u0435\u043C\u044F.", errorLoadingMessages: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0438\u0441\u0442\u043E\u0440\u0438\u044E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437 \u043F\u043E\u0437\u0436\u0435.", errorCreatingChat: "\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0438 \u0447\u0430\u0442\u0430. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437 \u043F\u043E\u0437\u0436\u0435.", errorSendingMessage: "\u0418\u0437\u0432\u0438\u043D\u0438\u0442\u0435, \u043F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437 \u043F\u043E\u0437\u0436\u0435.", threadNotFoundMessage: "\u0412\u0430\u0448 \u0447\u0430\u0442 \u0431\u044B\u043B \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D \u0438\u043B\u0438 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D. \u041D\u0430\u0447\u0438\u043D\u0430\u0435\u043C \u043D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442.", // Date formatting months: [ "\u042F\u043D\u0432\u0430\u0440\u044C", "\u0424\u0435\u0432\u0440\u0430\u043B\u044C", "\u041C\u0430\u0440\u0442", "\u0410\u043F\u0440\u0435\u043B\u044C", "\u041C\u0430\u0439", "\u0418\u044E\u043D\u044C", "\u0418\u044E\u043B\u044C", "\u0410\u0432\u0433\u0443\u0441\u0442", "\u0421\u0435\u043D\u0442\u044F\u0431\u0440\u044C", "\u041E\u043A\u0442\u044F\u0431\u0440\u044C", "\u041D\u043E\u044F\u0431\u0440\u044C", "\u0414\u0435\u043A\u0430\u0431\u0440\u044C" ] }; var oz = { // Header chatbotTitle: "AI suhbat boti", chatbotSubtitle: "Bizning AI-botimiz sizga 24/7 yordam berishga tayyor", // Welcome message welcomeGreeting: "Assalomu alaykum! \u{1F44B}", welcomeMessage: "Men Ali, Euroasia Insurance'dan sizning virtual yordamchingizman. Sug'urta olamida yo'l ko'rsatish, kerakli polisni tanlash yoki har qanday savollaringizga javob berishga tayyorman. Bemalol murojaat qiling! Bugun sizga qanday yordam bera olaman?", phoneRequestMessage: "Boshlash uchun, iltimos, telefon raqamingizni kiriting \u2014 biz undan aloqa va murojaat tarixini saqlash uchun foydalanamiz.", // Input placeholders phoneInputPlaceholder: "+ 998 (__) ___ __ __", phoneInputLabel: "Telefon raqamingizni kiriting", messageInputPlaceholder: "Sizning so'rovingiz", // Buttons sendButton: "Yuborish", callbackRequestButton: "Qayta qo'ng'iroq so'rovi", // Quick replies extendPolicyQuestion: "Polisni qanday uzaytirish mumkin?", findContractNumberQuestion: "Shartnoma raqamini qayerdan topish mumkin?", submitClaimQuestion: "Sug'urta hodisasi bo'yicha arizani qanday topshirish kerak?", // Callback modal callbackModalTitle: "Qayta qo'ng'iroq buyurtma qiling", callbackModalSubtitle: "Telefon raqamingizni qoldiring, va bizning mutaxassisimiz siz bilan yaqin vaqt ichida bog'lanadi", callbackPhoneInputLabel: "Telefon raqamini kiriting", dataPrivacyMessage: "Biz sizning ma'lumotlaringizni uchinchi shaxslarga bermaydi", dataProcessingConsent: "Shaxsiy ma'lumotlarni qayta ishlashga roziman", backButton: "Orqaga", requestCallButton: "Qo'ng'iroq buyurtma qilish", // Messages callbackConfirmation: "So'rov uchun rahmat! Mutaxassisimiz {phone} raqami orqali siz bilan yaqin vaqt ichida bog'lanadi.", errorLoadingMessages: "Xabarlar tarixini yuklab bo'lmadi. Iltimos, keyinroq qayta urinib ko'ring.", errorCreatingChat: "Chat yaratishda xatolik yuz berdi. Iltimos, keyinroq qayta urinib ko'ring.", errorSendingMessage: "Kechirasiz, xabar yuborishda xatolik yuz berdi. Iltimos, keyinroq qayta urinib ko'ring.", threadNotFoundMessage: "Sizning chatingiz tugatilgan yoki topilmadi. Yangi chat boshlaymiz.", // Date formatting months: [ "Yanvar", "Fevral", "Mart", "Aprel", "May", "Iyun", "Iyul", "Avgust", "Sentabr", "Oktabr", "Noyabr", "Dekabr" ] }; var uz = { // Header chatbotTitle: "AI \u0441\u0443\u04B3\u0431\u0430\u0442 \u0431\u043E\u0442\u0438", chatbotSubtitle: "\u0411\u0438\u0437\u043D\u0438\u043D\u0433 AI-\u0431\u043E\u0442\u0438\u043C\u0438\u0437 \u0441\u0438\u0437\u0433\u0430 24/7 \u0451\u0440\u0434\u0430\u043C \u0431\u0435\u0440\u0438\u0448\u0433\u0430 \u0442\u0430\u0439\u0451\u0440", // Welcome message welcomeGreeting: "\u0410\u0441\u0441\u0430\u043B\u043E\u043C\u0443 \u0430\u043B\u0430\u0439\u043A\u0443\u043C! \u{1F44B}", welcomeMessage: "\u041C\u0435\u043D \u0410\u043B\u0438, Euroasia Insurance'\u0434\u0430\u043D \u0441\u0438\u0437\u043D\u0438\u043D\u0433 \u0432\u0438\u0440\u0442\u0443\u0430\u043B \u0451\u0440\u0434\u0430\u043C\u0447\u0438\u043D\u0433\u0438\u0437\u043C\u0430\u043D. \u0421\u0443\u0493\u0443\u0440\u0442\u0430 \u043E\u043B\u0430\u043C\u0438\u0434\u0430 \u0439\u045E\u043B \u043A\u045E\u0440\u0441\u0430\u0442\u0438\u0448, \u043A\u0435\u0440\u0430\u043A\u043B\u0438 \u043F\u043E\u043B\u0438\u0441\u043D\u0438 \u0442\u0430\u043D\u043B\u0430\u0448 \u0451\u043A\u0438 \u04B3\u0430\u0440 \u049B\u0430\u043D\u0434\u0430\u0439 \u0441\u0430\u0432\u043E\u043B\u043B\u0430\u0440\u0438\u043D\u0433\u0438\u0437\u0433\u0430 \u0436\u0430\u0432\u043E\u0431 \u0431\u0435\u0440\u0438\u0448\u0433\u0430 \u0442\u0430\u0439\u0451\u0440\u043C\u0430\u043D. \u0411\u0435\u043C\u0430\u043B\u043E\u043B \u043C\u0443\u0440\u043E\u0436\u0430\u0430\u0442 \u049B\u0438\u043B\u0438\u043D\u0433! \u0411\u0443\u0433\u0443\u043D \u0441\u0438\u0437\u0433\u0430 \u049B\u0430\u043D\u0434\u0430\u0439 \u0451\u0440\u0434\u0430\u043C \u0431\u0435\u0440\u0430 \u043E\u043B\u0430\u043C\u0430\u043D?", phoneRequestMessage: "\u0411\u043E\u0448\u043B\u0430\u0448 \u0443\u0447\u0443\u043D, \u0438\u043B\u0442\u0438\u043C\u043E\u0441, \u0442\u0435\u043B\u0435\u0444\u043E\u043D \u0440\u0430\u049B\u0430\u043C\u0438\u043D\u0433\u0438\u0437\u043D\u0438 \u043A\u0438\u0440\u0438\u0442\u0438\u043D\u0433 \u2014 \u0431\u0438\u0437 \u0443\u043D\u0434\u0430\u043D \u0430\u043B\u043E\u049B\u0430 \u0432\u0430 \u043C\u0443\u0440\u043E\u0436\u0430\u0430\u0442 \u0442\u0430\u0440\u0438\u0445\u0438\u043D\u0438 \u0441\u0430\u049B\u043B\u0430\u0448 \u0443\u0447\u0443\u043D \u0444\u043E\u0439\u0434\u0430\u043B\u0430\u043D\u0430\u043C\u0438\u0437.", // Input placeholders phoneInputPlaceholder: "+ 998 (__) ___ __ __", phoneInputLabel: "\u0422\u0435\u043B\u0435\u0444\u043E\u043D \u0440\u0430\u049B\u0430\u043C\u0438\u043D\u0433\u0438\u0437\u043D\u0438 \u043A\u0438\u0440\u0438\u0442\u0438\u043D\u0433", messageInputPlaceholder: "\u0421\u0438\u0437\u043D\u0438\u043D\u0433 \u0441\u045E\u0440\u043E\u0432\u0438\u043D\u0433\u0438\u0437", // Buttons sendButton: "\u042E\u0431\u043E\u0440\u0438\u0448", callbackRequestButton: "\u049A\u0430\u0439\u0442\u0430 \u049B\u045E\u043D\u0493\u0438\u0440\u043E\u049B \u0441\u045E\u0440\u043E\u0432\u0438", // Quick replies extendPolicyQuestion: "\u041F\u043E\u043B\u0438\u0441\u043D\u0438 \u049B\u0430\u043D\u0434\u0430\u0439 \u0443\u0437\u0430\u0439\u0442\u0438\u0440\u0438\u0448 \u043C\u0443\u043C\u043A\u0438\u043D?", findContractNumberQuestion: "\u0428\u0430\u0440\u0442\u043D\u043E\u043C\u0430 \u0440\u0430\u049B\u0430\u043C\u0438\u043D\u0438 \u049B\u0430\u0435\u0440\u0434\u0430\u043D \u0442\u043E\u043F\u0438\u0448 \u043C\u0443\u043C\u043A\u0438\u043D?", submitClaimQuestion: "\u0421\u0443\u0493\u0443\u0440\u0442\u0430 \u04B3\u043E\u0434\u0438\u0441\u0430\u0441\u0438 \u0431\u045E\u0439\u0438\u0447\u0430 \u0430\u0440\u0438\u0437\u0430\u043D\u0438 \u049B\u0430\u043D\u0434\u0430\u0439 \u0442\u043E\u043F\u0448\u0438\u0440\u0438\u0448 \u043A\u0435\u0440\u0430\u043A?", // Callback modal callbackModalTitle: "\u049A\u0430\u0439\u0442\u0430 \u049B\u045E\u043D\u0493\u0438\u0440\u043E\u049B \u0431\u0443\u044E\u0440\u0442\u043C\u0430 \u049B\u0438\u043B\u0438\u043D\u0433", callbackModalSubtitle: "\u0422\u0435\u043B\u0435\u0444\u043E\u043D \u0440\u0430\u049B\u0430\u043C\u0438\u043D\u0433\u0438\u0437\u043D\u0438 \u049B\u043E\u043B\u0434\u0438\u0440\u0438\u043D\u0433, \u0432\u0430 \u0431\u0438\u0437\u043D\u0438\u043D\u0433 \u043C\u0443\u0442\u0430\u0445\u0430\u0441\u0441\u0438\u0441\u0438\u043C\u0438\u0437 \u0441\u0438\u0437 \u0431\u0438\u043B\u0430\u043D \u044F\u049B\u0438\u043D \u0432\u0430\u049B\u0442 \u0438\u0447\u0438\u0434\u0430 \u0431\u043E\u0493\u043B\u0430\u043D\u0430\u0434\u0438", callbackPhoneInputLabel: "\u0422\u0435\u043B\u0435\u0444\u043E\u043D \u0440\u0430\u049B\u0430\u043C\u0438\u043D\u0438 \u043A\u0438\u0440\u0438\u0442\u0438\u043D\u0433", dataPrivacyMessage: "\u0411\u0438\u0437 \u0441\u0438\u0437\u043D\u0438\u043D\u0433 \u043C\u0430\u044A\u043B\u0443\u043C\u043E\u0442\u043B\u0430\u0440\u0438\u043D\u0433\u0438\u0437\u043D\u0438 \u0443\u0447\u0438\u043D\u0447\u0438 \u0448\u0430\u0445\u0441\u043B\u0430\u0440\u0433\u0430 \u0431\u0435\u0440\u043C\u0430\u0439\u0434\u0438", dataProcessingConsent: "\u0428\u0430\u0445\u0441\u0438\u0439 \u043C\u0430\u044A\u043B\u0443\u043C\u043E\u0442\u043B\u0430\u0440\u043D\u0438 \u049B\u0430\u0439\u0442\u0430 \u0438\u0448\u043B\u0430\u0448\u0433\u0430 \u0440\u043E\u0437\u0438\u043C\u0430\u043D", backButton: "\u041E\u0440\u049B\u0430\u0433\u0430", requestCallButton: "\u049A\u045E\u043D\u0493\u0438\u0440\u043E\u049B \u0431\u0443\u044E\u0440\u0442\u043C\u0430 \u049B\u0438\u043B\u0438\u0448", // Messages callbackConfirmation: "\u0421\u045E\u0440\u043E\u0432 \u0443\u0447\u0443\u043D \u0440\u0430\u04B3\u043C\u0430\u0442! \u041C\u0443\u0442\u0430\u0445\u0430\u0441\u0441\u0438\u0441\u0438\u043C\u0438\u0437 {phone} \u0440\u0430\u049B\u0430\u043C\u0438 \u043E\u0440\u049B\u0430\u043B\u0438 \u0441\u0438\u0437 \u0431\u0438\u043B\u0430\u043D \u044F\u049B\u0438\u043D \u0432\u0430\u049B\u0442 \u0438\u0447\u0438\u0434\u0430 \u0431\u043E\u0493\u043B\u0430\u043D\u0430\u0434\u0438.", errorLoadingMessages: "\u0425\u0430\u0431\u0430\u0440\u043B\u0430\u0440 \u0442\u0430\u0440\u0438\u0445\u0438\u043D\u0438 \u044E\u043A\u043B\u0430\u0431 \u0431\u045E\u043B\u043C\u0430\u0434\u0438. \u0418\u043B\u0442\u0438\u043C\u043E\u0441, \u043A\u0435\u0439\u0438\u043D\u0440\u043E\u049B \u049B\u0430\u0439\u0442\u0430 \u0443\u0440\u0438\u043D\u0438\u0431 \u043A\u045E\u0440\u0438\u043D\u0433.", errorCreatingChat: "\u0427\u0430\u0442 \u044F\u0440\u0430\u0442\u0438\u0448\u0434\u0430 \u0445\u0430\u0442\u043E\u043B\u0438\u043A \u044E\u0437 \u0431\u0435\u0440\u0434\u0438. \u0418\u043B\u0442\u0438\u043C\u043E\u0441, \u043A\u0435\u0439\u0438\u043D\u0440\u043E\u049B \u049B\u0430\u0439\u0442\u0430 \u0443\u0440\u0438\u043D\u0438\u0431 \u043A\u045E\u0440\u0438\u043D\u0433.", errorSendingMessage: "\u041A\u0435\u0447\u0438\u0440\u0430\u0441\u0438\u0437, \u0445\u0430\u0431\u0430\u0440 \u044E\u0431\u043E\u0440\u0438\u0448\u0434\u0430 \u0445\u0430\u0442\u043E\u043B\u0438\u043A \u044E\u0437 \u0431\u0435\u0440\u0434\u0438. \u0418\u043B\u0442\u0438\u043C\u043E\u0441, \u043A\u0435\u0439\u0438\u043D\u0440\u043E\u049B \u049B\u0430\u0439\u0442\u0430 \u0443\u0440\u0438\u043D\u0438\u0431 \u043A\u045E\u0440\u0438\u043D\u0433.", threadNotFoundMessage: "\u0421\u0438\u0437\u043D\u0438\u043D\u0433 \u0447\u0430\u0442\u0438\u043D\u0433\u0438\u0437 \u0442\u0443\u0433\u0430\u0442\u0438\u043B\u0433\u0430\u043D \u0451\u043A\u0438 \u0442\u043E\u043F\u0438\u043B\u043C\u0430\u0434\u0438. \u042F\u043D\u0433\u0438 \u0447\u0430\u0442 \u0431\u043E\u0448\u043B\u0430\u0439\u043C\u0438\u0437.", // Date formatting months: [ "\u042F\u043D\u0432\u0430\u0440\u044C", "\u0424\u0435\u0432\u0440\u0430\u043B\u044C", "\u041C\u0430\u0440\u0442", "\u0410\u043F\u0440\u0435\u043B\u044C", "\u041C\u0430\u0439", "\u0418\u044E\u043D\u044C", "\u0418\u044E\u043B\u044C", "\u0410\u0432\u0433\u0443\u0441\u0442", "\u0421\u0435\u043D\u0442\u044F\u0431\u0440\u044C", "\u041E\u043A\u0442\u044F\u0431\u0440\u044C", "\u041D\u043E\u044F\u0431\u0440\u044C", "\u0414\u0435\u043A\u0430\u0431\u0440\u044C" ] }; var en = { // Header chatbotTitle: "AI chat bot", chatbotSubtitle: "Our AI bot is ready to help you 24/7", // Welcome message welcomeGreeting: "Hi there! \u{1F44B}", welcomeMessage: "I'm Ally, your virtual assistant from Euroasia Insurance. I'm ready to help you navigate the world of insurance, pick the right policy, or answer any questions you have. Feel free to ask! How can I help you today?", phoneRequestMessage: "To get started, please enter your phone number \u2014 we use it for communication and to save your request history.", // Input placeholders phoneInputPlaceholder: "+ 998 (__) ___ __ __", phoneInputLabel: "Enter your phone number", messageInputPlaceholder: "Your request", // Buttons sendButton: "Send", callbackRequestButton: "Request a callback", // Quick replies extendPolicyQuestion: "How to extend my policy?", findContractNumberQuestion: "Where to find my contract number?", submitClaimQuestion: "How to submit an insurance claim?", // Callback modal callbackModalTitle: "Request a callback", callbackModalSubtitle: "Leave your phone number, and our specialist will contact you shortly", callbackPhoneInputLabel: "Enter phone number", dataPrivacyMessage: "We don't share your data with third parties", dataProcessingConsent: "I agree to the processing of personal data", backButton: "Back", requestCallButton: "Request call", // Messages callbackConfirmation: "Thank you for your request! Our specialist will contact you at {phone} shortly.", errorLoadingMessages: "Failed to load message history. Please try again later.", errorCreatingChat: "An error occurred while creating the chat. Please try again later.", errorSendingMessage: "Sorry, an error occurred while sending the message. Please try again later.", threadNotFoundMessage: "Your chat has been ended or not found. Starting a new chat.", // Date formatting months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ] }; var translations = { ru, oz, uz, en }; function getTranslations(locale) { return translations[locale] || en; } var MOBILE_BREAKPOINT = 768; function useIsMobile() { const [isMobile, setIsMobile] = React.useState(void 0); React.useEffect(() => { const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); const onChange = () => { setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); }; mql.addEventListener("change", onChange); setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); return () => mql.removeEventListener("change", onChange); }, []); return !!isMobile; } function useSoundEffects(options = {}) { const { volume = 0.5, enabled = true, submitSoundPath = "/sounds/submit.mp3", operatorSoundPath = "/sounds/operator.mp3" } = options; const submitSoundRef = useRef(null); const operatorSoundRef = useRef(null); useEffect(() => { var _a, _b; if (typeof window !== "undefined" && enabled) { submitSoundRef.current = new Audio(submitSoundPath); operatorSoundRef.current = new Audio(operatorSoundPath); if (submitSoundRef.current) submitSoundRef.current.volume = volume; if (operatorSoundRef.current) operatorSoundRef.current.volume = volume; (_a = submitSoundRef.current) == null ? void 0 : _a.load(); (_b = operatorSoundRef.current) == null ? void 0 : _b.load(); } return () => { submitSoundRef.current = null; operatorSoundRef.current = null; }; }, [enabled, volume, submitSoundPath, operatorSoundPath]); const playSubmitSound = useCallback(() => { if (enabled && submitSoundRef.current) { submitSoundRef.current.currentTime = 0; submitSoundRef.current.play().catch(() => { }); } }, [enabled]); const playOperatorSound = useCallback(() => { if (enabled && operatorSoundRef.current) { operatorSoundRef.current.currentTime = 0; operatorSoundRef.current.play().catch(() => { }); } }, [enabled]); return { playSubmitSound, playOperatorSound }; } var TOAST_LIMIT = 1; var TOAST_REMOVE_DELAY = 4e3; var count = 0; function genId() { count = (count + 1) % Number.MAX_SAFE_INTEGER; return count.toString(); } var toastTimeouts = /* @__PURE__ */ new Map(); var addToRemoveQueue = (toastId) => { if (toastTimeouts.has(toastId)) { return; } const timeout = setTimeout(() => { toastTimeouts.delete(toastId); dispatch({ type: "REMOVE_TOAST", toastId }); }, TOAST_REMOVE_DELAY); toastTimeouts.set(toastId, timeout); }; var reducer = (state, action) => { switch (action.type) { case "ADD_TOAST": return __spreadProps(__spreadValues({}, state), { toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT) }); case "UPDATE_TOAST": return __spreadProps(__spreadValues({}, state), { toasts: state.toasts.map( (t) => t.id === action.toast.id ? __spreadValues(__spreadValues({}, t), action.toast) : t ) }); case "DISMISS_TOAST": { const { toastId } = action; if (toastId) { addToRemoveQueue(toastId); } else { state.toasts.forEach((toast2) => { addToRemoveQueue(toast2.id); }); } return __spreadProps(__spreadValues({}, state), { toasts: state.toasts.map( (t) => t.id === toastId || toastId === void 0 ? __spreadProps(__spreadValues({}, t), { open: false }) : t ) }); } case "REMOVE_TOAST": if (action.toastId === void 0) { return __spreadProps(__spreadValues({}, state), { toasts: [] }); } return __spreadProps(__spreadValues({}, state), { toasts: state.toasts.filter((t) => t.id !== action.toastId) }); } }; var listeners = []; var memoryState = { toasts: [] }; function dispatch(action) { memoryState = reducer(memoryState, action); listeners.forEach((listener) => { listener(memoryState); }); } function toast(_a) { var props = __objRest(_a, []); const id = genId(); const update = (props2) => dispatch({ type: "UPDATE_TOAST", toast: __spreadProps(__spreadValues({}, props2), { id }) }); const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); dispatch({ type: "ADD_TOAST", toast: __spreadProps(__spreadValues({}, props), { id, open: true, onOpenChange: (open) => { if (!open) dismiss(); } }) }); return { id, dismiss, update }; } function useToast() { const [state, setState] = React.useState(memoryState); React.useEffect(() => { listeners.push(setState); return () => { const index = listeners.indexOf(setState); if (index > -1) { listeners.splice(index, 1); } }; }, [state]); return __spreadProps(__spreadValues({}, state), { toast, dismiss: (toastId) => dispatch({ type: "DISMISS_TOAST", toastId }) }); } var ChatHeader = ({ title, subtitle, chatIcon, onClose, isMobile }) => { return /* @__PURE__ */ React__default.createElement( "div", { className: "relative bg-[#0a223e] text-white p-4 flex items-center", style: { height: "60px" } }, /* @__PURE__ */ React__default.createElement("div", { className: "w-10 h-10 rounded-full flex items-center justify-center mr-3" }, chatIcon ? chatIcon : /* @__PURE__ */ React__default.createElement("span", { className: "text-white" }, "\u2022\u2022\u2022")), /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement("h4", { className: "text-xl font-medium" }, title), /* @__PURE__ */ React__default.createElement("p", { className: "text-sm opacity-90" }, subtitle)), /* @__PURE__ */ React__default.createElement( "div", { className: "absolute right-4 top-1/2 transform -translate-y-1/2 cursor-pointer", onClick: onClose }, /* @__PURE__ */ React__default.createElement( X, { className: "transition-transform duration-300", size: isMobile ? 28 : 24 } ) ) ); }; var ChatFloatingButton = ({ onClick, isMobile, messageCount, chatIcon }) => { return /* @__PURE__ */ React__default.createElement( "div", { className: "w-16 h-16 bg-[#0a223e] rounded-full shadow-lg flex items-center justify-center cursor-pointer hover:bg-[#1e3b66] transition-all duration-300 hover:scale-110 ml-auto pointer-events-auto", onClick, style: { position: isMobile ? "fixed" : "relative", bottom: isMobile ? "20px" : "auto", right: isMobile ? "20px" : "auto" } }, /* @__PURE__ */ React__default.createElement("div", { className: "relative" }, chatIcon ? chatIcon : /* @__PURE__ */ React__default.createElement(MessageCircle, { className: "text-white", size: 28 }), /* @__PURE__ */ React__default.createElement("span", { className: "absolute -top-1 -right-1 flex h-5 w-5 items-center justify-center rounded-full bg-red-500 text-xs text-white" }, messageCount)) ); }; var MessageBubble = ({ message, translations: translations2, botTitle }) => { return /* @__PURE__ */ React__default.createElement( "div", { className: `max-w-[80%] w-fit ${message.sender === "user" ? "ml-auto bg-[#dce6f3] rounded-tl-2xl rounded-tr-2xl rounded-bl-2xl p-3" : "bg-white rounded-tr-2xl rounded-tl-2xl rounded-br-xl p-4 shadow-sm"}` }, message.sender === "bot" && /* @__PURE__ */ React__default.createElement("div", { className: "text-[#2e67b4] font-medium mb-2" }, botTitle || translations2.chatbotTitle), message.sender === "bot" ? /* @__PURE__ */ React__default.createElement("div", { className: "markdown-content" }, /* @__PURE__ */ React__default.createElement( ReactMarkdown, { remarkPlugins: [remarkGfm], components: { a: (_a) => { var _b = _a, { node } = _b, props = __objRest(_b, ["node"]); return /* @__PURE__ */ React__default.createElement("a", __spreadValues({ target: "_blank", rel: "noopener noreferrer" }, props)); } } }, message.content )) : /* @__PURE__ */ React__default.createElement("p", { className: "whitespace-pre-line" }, message.content) ); }; var MessageInput = ({ currentMessage, setCurrentMessage, handleSubmit, handleKeyPress, isTyping, translations: translations2, isMobile, onMessageSubmit }) => { return /* @__PURE__ */ React__default.createElement("div", { className: "flex items-center p-3 mb-4 bg-[#f2f5f8] rounded-lg" }, /* @__PURE__ */ React__default.createElement( "input", { type: "text", className: "bg-transparent focus:outline-none text-[#0a223e] flex-1", placeholder: translations2.messageInputPlaceholder, value: currentMessage, onChange: (e) => setCurrentMessage(e.target.value), onKeyDown: handleKeyPress, disabled: isTyping, style: { fontSize: isMobile ? "16px" : "inherit" } } ), /* @__PURE__ */ React__default.createElement( "button", { onClick: () => { handleSubmit(); if (onMessageSubmit && currentMessage.trim().length > 0) { onMessageSubmit(currentMessage.trim()); } }, disabled: isTyping || currentMessage.trim().length === 0 }, /* @__PURE__ */ React__default.createElement( Send, { className: `ml-auto ${currentMessage.trim() && !isTyping ? "text-[#0a223e]" : "text-[#8b98a5]"}`, size: isMobile ? 24 : 20 } ) )); }; var PhoneInput = ({ phoneNumber, setPhoneNumber, handleSubmit, handleKeyPress, isTyping, translations: translations2, isMobile, error }) => { const isValid = phoneNumber && phoneNumber.replace(/[^0-9]/g, "").length === 12; const maskOptions = { mask: "+998 __ ___ __ __", replacement: { _: /\d/ } }; const handleChange = (e) => { const maskedValue = e.target.value; const digitsOnly = maskedValue.replace(/[^0-9]/g, "").length; if (digitsOnly > 3) { setPhoneNumber(maskedValue); } else { setPhoneNumber("+998"); } }; const handleClick = (e) => { const input = e.currentTarget; if (input.value === "+998 __ ___ __ __" || input.value === "+998") { setTimeout(() => { input.setSelectionRange(6, 6); }, 0); } }; const displayValue = phoneNumber && phoneNumber.replace(/[^0-9]/g, "").length > 3 ? phoneNumber : "+998 __ ___ __ __"; return /* @__PURE__ */ React__default.createElement("div", { className: "mb-4" }, /* @__PURE__ */ React__default.createElement("label", { htmlFor: "phone-input", className: "block mb-2 text-sm font-medium text-[#0a223e]" }, translations2.phoneInputLabel), /* @__PURE__ */ React__default.createElement("div", { className: `flex items-center p-3 ${error ? "bg-red-50 border border-red-300" : "bg-[#f2f5f8]"} rounded-lg` }, /* @__PURE__ */ React__default.createElement( InputMask, { id: "phone-input", mask: maskOptions.mask, replacement: maskOptions.replacement, showMask: true, className: "bg-transparent focus:outline-none text-[#0a223e] flex-1", value: displayValue, onChange: handleChange, onKeyDown: handleKeyPress, onClick: handleClick, style: { fontSize: isMobile ? "16px" : "inherit" }, "aria-invalid": error ? "true" : "false" } ), /* @__PURE__ */ React__default.createElement( "button", { onClick: handleSubmit, disabled: isTyping || !isValid || phoneNumber === "+998 __ ___ __ __" || phoneNumber === "+998" }, /* @__PURE__ */ React__default.createElement( Send, { className: `ml-auto ${isTyping || !isValid || phoneNumber === "+998 __ ___ __ __" || phoneNumber === "+998" ? "text-[#8b98a5]" : "text-[#0a223e]"}`, size: isMobile ? 24 : 20 } ) )), error && /* @__PURE__ */ React__default.createElement("div", { className: "mt-1 text-sm text-red-600", role: "alert" }, error)); }; var WelcomeMessage = ({ chatbotTitle, translations: translations2 }) => { return /* @__PURE__ */ React__default.createElement("div", { className: "bg-white rounded-tr-2xl rounded-tl-2xl rounded-br-xl p-4 shadow-sm" }, /* @__PURE__ */ React__default.createElement("div", { className: "text-[#2e67b4] font-medium mb-2" }, chatbotTitle), /* @__PURE__ */ React__default.createElement("p", { className: "mb-2" }, translations2.welcomeGreeting), /* @__PURE__ */ React__default.createElement("p", { className: "mb-4" }, translations2.welcomeMessage), /* @__PURE__ */ React__default.createElement("p", { className: "flex items-start" }, /* @__PURE__ */ React__default.createElement("span", { className: "inline-block mr-2 mt-1" }, "\u{1F512}"), /* @__PURE__ */ React__default.createElement("span", null, translations2.phoneRequestMessage))); }; // components/chatbot-interface.tsx function ChatbotInterface({ locale = "ru", apiEndpoint, // Direct API endpoint (required) faqItems, title, subtitle, chatIcon, customButton, soundOptions, onMessageSubmit }) { const translations2 = getTranslations(locale); const isMobile = useIsMobile(); const { playSubmitSound, playOperatorSound } = useSoundEffects(soundOptions); const { toast: toast2 } = useToast(); useEffect(() => { if (apiEndpoint) { chatApi.setApiEndpoint(apiEndpoint); } }, [apiEndpoint]); const [phoneSubmitted, setPhoneSubmitted] = useState(false); const [phoneNumber, setPhoneNumber] = useState(""); const [phoneError, setPhoneError] = useState(void 0); const handlePhoneNumberChange = (value) => { setPhoneNumber(value); if (phoneError) { setPhoneError(void 0); } }; const [messages, setMessages] = useState([]); const [currentMessage, setCurrentMessage] = useState(""); const [showDateHeader, setShowDateHeader] = useState(false); const [isCallbackModalOpen, setIsCallbackModalOpen] = useState(false); const [isTyping, setIsTyping] = useState(false); const [threadId, setThreadId] = useState(null); const messagesEndRef = useRef(null); const [isOpen, setIsOpen] = useState(false); const [messageCount, setMessageCount] = useState(1); const [windowHeight, setWindowHeight] = useState(0); const chatbotTitle = title || translations2.chatbotTitle; const chatbotSubtitle = subtitle || translations2.chatbotSubtitle; const handleResetChat = useCallback(() => { localStorage.removeItem("chatThreadId"); setThreadId(null); setPhoneSubmitted(false); setPhoneNumber(""); const now = /* @__PURE__ */ new Date(); setMessages([ { id: "welcome", content: `${translations2.welcomeGreeting} ${translations2.welcomeMessage}`, sender: "bot", timestamp: now } ]); }, [translations2]); const handle404Error = useCallback(() => { const now = /* @__PURE__ */ new Date(); const errorMsg = { id: `bot-error-${Date.now()}`, content: translations2.threadNotFoundMessage, sender: "bot", timestamp: now }; setMessages([errorMsg]); handleResetChat(); }, [translations2, handleResetChat]); const fetchMessages = useCallback((threadId2) => __async(null, null, function* () { try { setIsTyping(true); const response = yield chatApi.getMessages(threadId2); const chatMessages = response.messages.map((msg, index) => ({ id: `${msg.role}-${index}`, content: msg.message, sender: msg.role === "user" ? "user" : "bot", timestamp: new Date(msg.timestamp) // Parse ISO timestamp from API })); setMessages(chatMessages); } catch (error) { if (error instanceof ApiError) { if (error.hasOneOfCodes(["NOT_FOUND", "THREAD_NOT_FOUND"])) { handle404Error(); return; } toast2({ variant: "destructive", title: translations2.errorLoadingMessages, description: error.message }); } else { const errorMessage = error instanceof Error ? error.message : String(error); if (error instanceof Error && errorMessage.includes("404")) { handle404Error(); return; } toast2({ variant: "destructive", title: translations2.errorLoadingMessages, description: errorMessage }); } const now = /* @__PURE__ */ new Date(); setMessages([ { id: "error", content: translations2.errorLoadingMessages, sender: "bot", timestamp: now } ]); } finally { setIsTyping(false); } }), [handle404Error, toast2, translations2]); useEffect(() => { const updateWindowHeight = () => { setTimeout(() => { setWindowHeight(window.innerHeight); }, 100); }; updateWindowHeight(); window.addEventListener("resize", updateWindowHeight); if (typeof window !== "undefined") { window.addEventListener("orientationchange", () => { setTimeout(updateWindowHeight, 300); }); } return () => { window.removeEventListener("resize", updateWindowHeight); if (typeof window !== "undefined") { window.removeEventListener("orientationchange", updateWindowHeight); } }; }, [isMobile]); useEffect(() => { const storedThreadId = localStorage.getItem("chatThreadId"); if (storedThreadId) { setThreadId(storedThreadId); setPhoneSubmitted(true); setShowDateHeader(true); fetchMessages(storedThreadId); } else { const now = /* @__PURE__ */ new Date(); setMessages([ { id: "welcome", content: `${translations2.welcomeGreeting} ${translations2.welcomeMessage}`, sender: "bot", timestamp: now } ]); } }, [translations2, fetchMessages]); useEffect(() => { var _a; (_a = messag