aizek-chatbot 1.0.26 → 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -4,13 +4,20 @@ var react = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var ReactMarkdown = require('react-markdown');
6
6
  var remarkGfm = require('remark-gfm');
7
+ var sanitizeHtml = require('sanitize-html');
7
8
 
8
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
10
 
10
11
  var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
11
12
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
13
+ var sanitizeHtml__default = /*#__PURE__*/_interopDefault(sanitizeHtml);
12
14
 
13
- // src/utils/cx.ts
15
+ // src/utils/global.ts
16
+ var SESSION_TTL_MS = 60 * 60 * 1e3;
17
+ var MAX_SESSIONS = 3;
18
+ var DEVICE_KEY = "aizek_device_id_v1";
19
+ var ACTIVE_SESSION_KEY = "aizek_active_session_v1";
20
+ var LOCAL_SESSIONS_KEY = "aizek_sessions_v1";
14
21
  function validateHeaders(headers, authConfig, opts = {}) {
15
22
  if (headers && (!authConfig || Object.keys(authConfig).length === 0)) {
16
23
  return {
@@ -39,6 +46,65 @@ function validateHeaders(headers, authConfig, opts = {}) {
39
46
  const isValid = hasAllRequired && !hasExtraKeys && emptyValueKeys.length === 0;
40
47
  return { isValid, missingKeys, extraKeys, emptyValueKeys };
41
48
  }
49
+ function getOrCreateDeviceId() {
50
+ if (typeof window === "undefined") return "";
51
+ const existing = localStorage.getItem(DEVICE_KEY);
52
+ if (existing) return existing;
53
+ const id = crypto.randomUUID();
54
+ localStorage.setItem(DEVICE_KEY, id);
55
+ return id;
56
+ }
57
+ function now() {
58
+ return Date.now();
59
+ }
60
+ function readStoredSessions() {
61
+ try {
62
+ const raw = localStorage.getItem(LOCAL_SESSIONS_KEY);
63
+ const parsed = JSON.parse(raw ?? "[]");
64
+ if (!Array.isArray(parsed)) return [];
65
+ return parsed.filter((x) => x && typeof x.sessionId === "string" && typeof x.lastActive === "number").slice(0, MAX_SESSIONS);
66
+ } catch {
67
+ return [];
68
+ }
69
+ }
70
+ function writeStoredSessions(list) {
71
+ localStorage.setItem(LOCAL_SESSIONS_KEY, JSON.stringify(list.slice(0, MAX_SESSIONS)));
72
+ }
73
+ function purgeExpiredLocalSessions(setActiveSessionIdState) {
74
+ const list = readStoredSessions();
75
+ const filtered = list.filter((s) => now() - s.lastActive <= SESSION_TTL_MS);
76
+ if (filtered.length !== list.length) writeStoredSessions(filtered);
77
+ const active = getActiveSessionId();
78
+ if (active && !filtered.some((s) => s.sessionId === active)) {
79
+ setActiveSessionId(null);
80
+ setActiveSessionIdState(null);
81
+ }
82
+ return filtered;
83
+ }
84
+ function getActiveSessionId() {
85
+ return localStorage.getItem(ACTIVE_SESSION_KEY);
86
+ }
87
+ function setActiveSessionId(id) {
88
+ if (!id) localStorage.removeItem(ACTIVE_SESSION_KEY);
89
+ else localStorage.setItem(ACTIVE_SESSION_KEY, id);
90
+ }
91
+ function touchSession(sessionId) {
92
+ const list = readStoredSessions();
93
+ const next = list.map((s) => s.sessionId === sessionId ? { ...s, lastActive: now() } : s);
94
+ if (!next.some((s) => s.sessionId === sessionId)) next.unshift({ sessionId, lastActive: now() });
95
+ writeStoredSessions(next.slice(0, MAX_SESSIONS));
96
+ }
97
+ function upsertSessionsFromServer(serverSessionIds, setSessions) {
98
+ const local = readStoredSessions();
99
+ const map = new Map(local.map((s) => [s.sessionId, s.lastActive]));
100
+ const merged = serverSessionIds.slice(0, MAX_SESSIONS).map((sid) => ({
101
+ sessionId: sid,
102
+ lastActive: map.get(sid) ?? now()
103
+ }));
104
+ writeStoredSessions(merged);
105
+ setSessions(merged.map((x) => x.sessionId));
106
+ return merged;
107
+ }
42
108
  var HeaderAlert = ({ headerValidation, showAlert, setShowAlert }) => {
43
109
  if (!headerValidation || !showAlert) return null;
44
110
  const { isValid, missingKeys, extraKeys, emptyValueKeys, warning } = headerValidation;
@@ -429,7 +495,17 @@ var extractUIJsonFromText = (text) => {
429
495
  uiData
430
496
  };
431
497
  };
432
- var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, onMessage, onToolCall, onDisconnect }) => {
498
+ var AizekChatBot = ({
499
+ clientId,
500
+ headers,
501
+ onMounted,
502
+ onReady,
503
+ onOpen,
504
+ onClose,
505
+ onMessage,
506
+ onToolCall,
507
+ onDisconnect
508
+ }) => {
433
509
  const messagesEndRef = react.useRef(null);
434
510
  const [config, setConfig] = react.useState();
435
511
  const [messages, setMessages] = react.useState([]);
@@ -438,78 +514,169 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
438
514
  const [isOpen, setIsOpen] = react.useState(false);
439
515
  const [headerValidation, setHeaderValidation] = react.useState(null);
440
516
  const [showAlert, setShowAlert] = react.useState(true);
517
+ const [sessions, setSessions] = react.useState([]);
518
+ const [activeSessionId, setActiveSessionIdState] = react.useState(null);
519
+ const [activeTab, setActiveTab] = react.useState("home");
520
+ const [messageView, setMessageView] = react.useState("list");
441
521
  const PROXY_BASE_URL = "https://proxy.aizek.ai/api";
522
+ const createNewSession = async () => {
523
+ const deviceId = getOrCreateDeviceId();
524
+ if (sessions.length >= MAX_SESSIONS) {
525
+ throw new Error(`You can open up to ${MAX_SESSIONS} sessions.`);
526
+ }
527
+ const res = await fetch(`${PROXY_BASE_URL}/aizek-sessions/new?clientId=${clientId}`, {
528
+ method: "POST",
529
+ headers: {
530
+ "Content-Type": "application/json",
531
+ "x-device-id": deviceId,
532
+ "x-alternate": JSON.stringify(headers)
533
+ }
534
+ });
535
+ const data = await res.json();
536
+ if (!data.success) throw new Error(data.message || "session create failed");
537
+ const sid = data.data.sessionId;
538
+ const updatedSessions = data.data.sessions ?? [sid];
539
+ upsertSessionsFromServer(updatedSessions, setSessions);
540
+ setActiveSessionIdState(sid);
541
+ setActiveSessionId(sid);
542
+ setActiveTab("messages");
543
+ setMessageView("detail");
544
+ touchSession(sid);
545
+ setMessages([]);
546
+ return sid;
547
+ };
442
548
  const loadConfig = async () => {
443
549
  try {
444
550
  setIsConfigLoading(true);
445
- const response = await fetch(`${PROXY_BASE_URL}/aizek-connect`, {
551
+ const deviceId = getOrCreateDeviceId();
552
+ purgeExpiredLocalSessions(setActiveSessionIdState);
553
+ const localActive = getActiveSessionId();
554
+ const response = await fetch(`${PROXY_BASE_URL}/aizek-connect?clientId=${clientId}`, {
446
555
  method: "POST",
447
556
  headers: {
448
557
  "Content-Type": "application/json",
558
+ "x-device-id": deviceId,
449
559
  "x-alternate": JSON.stringify(headers)
450
- },
451
- credentials: "include",
452
- body: JSON.stringify({ clientId })
560
+ }
453
561
  });
454
562
  const data = await response.json();
455
- if (data.success) {
456
- setIsOpen(data.data.widget_config.initial_open);
457
- setConfig(data.data);
458
- if (headers) {
459
- const validationResult = validateHeaders(
460
- headers,
461
- data.data.auth_config,
462
- {
463
- allowExtra: false,
464
- caseSensitive: true
465
- }
466
- );
467
- setHeaderValidation(validationResult);
468
- }
469
- onReady?.({ config: { ...data.data } });
470
- } else {
563
+ if (!data.success) {
471
564
  setIsOpen(false);
565
+ return;
566
+ }
567
+ setIsOpen(!!data.data.widget_config.initial_open);
568
+ setConfig(data.data);
569
+ const serverSessions = data.data.sessions ?? [];
570
+ const merged = upsertSessionsFromServer(serverSessions, setSessions);
571
+ if (merged.length === 0) {
572
+ const newSid = await createNewSession();
573
+ setActiveSessionIdState(newSid);
574
+ setActiveSessionId(newSid);
575
+ return;
576
+ }
577
+ const mergedIds = merged.map((s) => s.sessionId);
578
+ const nextActive = (localActive && mergedIds.includes(localActive) ? localActive : null) ?? mergedIds[0] ?? null;
579
+ setActiveSessionIdState(nextActive);
580
+ setActiveSessionId(nextActive);
581
+ if (headers) {
582
+ const validationResult = validateHeaders(headers, data.data.auth_config, {
583
+ allowExtra: false,
584
+ caseSensitive: true
585
+ });
586
+ setHeaderValidation(validationResult);
472
587
  }
588
+ onReady?.({ config: { ...data.data } });
473
589
  } catch (error) {
474
590
  console.error("Failed to load chat widget config:", error);
475
591
  } finally {
476
592
  setIsConfigLoading(false);
477
593
  }
478
594
  };
479
- const disconnect = async () => {
595
+ const getHistoryMessageBySessionId = async (sid) => {
480
596
  try {
481
- setIsConfigLoading(true);
482
- await fetch(`${PROXY_BASE_URL}/aizek-disconnect`, {
483
- method: "POST",
597
+ const deviceId = getOrCreateDeviceId();
598
+ const response = await fetch(`${PROXY_BASE_URL}/aizek-messages`, {
599
+ method: "GET",
484
600
  headers: {
485
601
  "Content-Type": "application/json",
602
+ "x-device-id": deviceId,
603
+ "x-session-id": sid,
486
604
  "x-alternate": JSON.stringify(headers)
487
- },
488
- credentials: "include"
605
+ }
489
606
  });
490
- onDisconnect?.();
607
+ const data = await response.json();
608
+ if (!data.success) {
609
+ throw new Error(data.message || "Failed to fetch messages");
610
+ }
611
+ const historyMessages = [];
612
+ if (data.data?.messages && Array.isArray(data.data.messages)) {
613
+ for (const msg of data.data.messages) {
614
+ let textContent = "";
615
+ let uiData = null;
616
+ if (typeof msg.content === "string") {
617
+ textContent = msg.content;
618
+ } else if (Array.isArray(msg.content)) {
619
+ const textParts = [];
620
+ for (const item of msg.content) {
621
+ if (item.type === "text" && item.text) {
622
+ textParts.push(item.text);
623
+ }
624
+ }
625
+ textContent = textParts.join("\n");
626
+ }
627
+ if (textContent) {
628
+ const extracted = extractUIJsonFromText(textContent);
629
+ textContent = extracted.cleanedText;
630
+ uiData = extracted.uiData;
631
+ }
632
+ if (textContent.trim() || uiData) {
633
+ historyMessages.push({
634
+ text: textContent.trim() || void 0,
635
+ ui: uiData,
636
+ role: msg.role === "user" ? "user" : msg.role === "assistant" ? "assistant" : "user",
637
+ timestamp: /* @__PURE__ */ new Date()
638
+ });
639
+ }
640
+ }
641
+ }
642
+ return historyMessages;
491
643
  } catch (error) {
492
- console.error("Failed to load chat widget config:", error);
493
- } finally {
494
- setIsConfigLoading(false);
644
+ console.error("Error fetching message history:", error);
645
+ return [];
495
646
  }
496
647
  };
497
648
  react.useEffect(() => {
498
649
  onMounted?.();
499
650
  loadConfig();
500
- return () => {
501
- disconnect();
502
- };
503
651
  }, []);
504
652
  react.useEffect(() => {
505
- const newIsOpen = !isOpen;
506
- setIsOpen(newIsOpen);
507
- if (newIsOpen) onOpen?.();
508
- else onClose?.();
653
+ const t = setInterval(() => {
654
+ purgeExpiredLocalSessions(setActiveSessionIdState);
655
+ }, 1e3);
656
+ return () => clearInterval(t);
657
+ }, []);
658
+ react.useEffect(() => {
659
+ if (typeof config?.widget_config.initial_open === "boolean") {
660
+ const open = config.widget_config.initial_open;
661
+ setIsOpen(open);
662
+ if (open) onOpen?.();
663
+ else onClose?.();
664
+ }
509
665
  }, [config?.widget_config.initial_open]);
510
666
  react.useEffect(() => {
511
667
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
512
668
  }, [messages]);
669
+ react.useEffect(() => {
670
+ if (activeSessionId && !isConfigLoading) {
671
+ getHistoryMessageBySessionId(activeSessionId).then((historyMessages) => {
672
+ setMessages(historyMessages);
673
+ }).catch((error) => {
674
+ console.error("Failed to load message history:", error);
675
+ });
676
+ } else if (!activeSessionId) {
677
+ setMessages([]);
678
+ }
679
+ }, [activeSessionId, isConfigLoading]);
513
680
  const addMessage = (payload) => {
514
681
  const newMessage = {
515
682
  text: payload.text,
@@ -524,24 +691,51 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
524
691
  };
525
692
  const sendMessage = async (message, approval) => {
526
693
  if (!message.trim() || isLoading) return;
527
- const newMessage = {
528
- text: message,
529
- ui: void 0,
530
- role: approval ? "approval" : "user",
531
- timestamp: /* @__PURE__ */ new Date()
532
- };
533
- setMessages((prev) => [...prev, newMessage]);
694
+ setMessages((prev) => [
695
+ ...prev,
696
+ { text: message, ui: void 0, role: approval ? "approval" : "user", timestamp: /* @__PURE__ */ new Date() }
697
+ ]);
534
698
  setIsLoading(true);
535
699
  try {
536
- const response = await fetch(`${PROXY_BASE_URL}/aizek-chat`, {
700
+ const deviceId = getOrCreateDeviceId();
701
+ purgeExpiredLocalSessions(setActiveSessionIdState);
702
+ let sid = activeSessionId;
703
+ if (!sid) sid = await createNewSession();
704
+ const response = await fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
537
705
  method: "POST",
538
706
  headers: {
539
707
  "Content-Type": "application/json",
708
+ "x-device-id": deviceId,
709
+ "x-session-id": sid,
540
710
  "x-alternate": JSON.stringify(headers)
541
711
  },
542
- body: JSON.stringify({ message }),
543
- credentials: "include"
712
+ body: JSON.stringify({ message })
544
713
  });
714
+ if (response.status === 401) {
715
+ const local = readStoredSessions().filter((s) => s.sessionId !== sid);
716
+ writeStoredSessions(local);
717
+ setSessions(local.map((x) => x.sessionId));
718
+ setActiveSessionId(null);
719
+ setActiveSessionIdState(null);
720
+ const newSid = await createNewSession();
721
+ const retry = await fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
722
+ method: "POST",
723
+ headers: {
724
+ "Content-Type": "application/json",
725
+ "x-device-id": deviceId,
726
+ "x-session-id": newSid,
727
+ "x-alternate": JSON.stringify(headers)
728
+ },
729
+ body: JSON.stringify({ message })
730
+ });
731
+ if (!retry.ok) throw new Error(`HTTP error ${retry.status}`);
732
+ const retryJson = await retry.json();
733
+ const text = JSON.stringify(retryJson.data);
734
+ const { cleanedText, uiData } = extractUIJsonFromText(text);
735
+ addMessage({ text: cleanedText, ui: uiData, role: "assistant" });
736
+ touchSession(newSid);
737
+ return;
738
+ }
545
739
  if (!response.ok) {
546
740
  throw new Error(`HTTP error ${response.status}`);
547
741
  }
@@ -585,87 +779,359 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
585
779
  }
586
780
  }
587
781
  }
782
+ touchSession(sid);
588
783
  } catch (error) {
589
784
  console.error("Error sending message:", error);
590
- addMessage({ text: "\xDCzg\xFCn\xFCm, bir hata olu\u015Ftu. L\xFCtfen tekrar deneyin.", role: "assistant" });
785
+ addMessage({ text: "Sorry, something went wrong. Please try again.", role: "assistant" });
591
786
  } finally {
592
787
  setIsLoading(false);
593
788
  }
594
789
  };
790
+ const disconnectActiveSession = async () => {
791
+ try {
792
+ const deviceId = getOrCreateDeviceId();
793
+ const sid = activeSessionId;
794
+ if (!sid) return;
795
+ await fetch(`${PROXY_BASE_URL}/aizek-disconnect?clientId=${clientId}`, {
796
+ method: "POST",
797
+ headers: {
798
+ "Content-Type": "application/json",
799
+ "x-device-id": deviceId,
800
+ "x-session-id": sid,
801
+ "x-alternate": JSON.stringify(headers)
802
+ },
803
+ body: JSON.stringify({ sessionId: sid })
804
+ });
805
+ const nextStored = readStoredSessions().filter((s) => s.sessionId !== sid);
806
+ writeStoredSessions(nextStored);
807
+ const nextSessions = nextStored.map((x) => x.sessionId);
808
+ setSessions(nextSessions);
809
+ const nextActive = nextSessions[0] ?? null;
810
+ setActiveSessionIdState(nextActive);
811
+ setActiveSessionId(nextActive);
812
+ setMessages([]);
813
+ onDisconnect?.();
814
+ } catch (e) {
815
+ console.error(e);
816
+ }
817
+ };
818
+ const handleSelectSession = (sid) => {
819
+ setActiveSessionIdState(sid);
820
+ setActiveSessionId(sid);
821
+ setActiveTab("messages");
822
+ setMessageView("detail");
823
+ };
824
+ const getSessionLabel = (sid) => {
825
+ const idx = sessions.indexOf(sid);
826
+ return idx >= 0 ? `Chat ${idx + 1}` : "Chat";
827
+ };
595
828
  const toggleChat = () => {
596
829
  const newIsOpen = !isOpen;
597
830
  setIsOpen(newIsOpen);
598
831
  if (newIsOpen) onOpen?.();
599
832
  else onClose?.();
600
833
  };
834
+ const clean = sanitizeHtml__default.default(config?.widget_config.welcome_message ?? "", {
835
+ allowedTags: ["b", "i", "em", "strong", "a", "p", "br"],
836
+ allowedAttributes: {
837
+ a: ["href", "target", "rel"]
838
+ }
839
+ });
601
840
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: isConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx(
602
841
  "button",
603
842
  {
604
843
  className: "floating-button bottom-right button-sizes medium loading-state",
605
844
  style: { background: "#4f46e5" },
606
- "aria-label": "Y\xFCkleniyor",
845
+ "aria-label": "Loading",
607
846
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loading-spinner" })
608
847
  }
609
848
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
610
849
  isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `overlay floating-chat-overlay ${isOpen ? "is-open" : ""}`, onClick: toggleChat }),
611
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `chat-container ${config?.widget_config.button_position} ${isOpen ? "is-open" : ""}`, style: { width: config?.widget_config.chat_width, height: config?.widget_config.chat_height }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatbot-container", children: [
612
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "header", style: { background: config?.widget_config.header_background }, children: [
613
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "logo-container", children: config?.widget_config.company_logo ? config?.widget_config.company_logo.startsWith("http") || config?.widget_config.company_logo.startsWith("data:") ? /* @__PURE__ */ jsxRuntime.jsx(
614
- "img",
615
- {
616
- src: config?.widget_config.company_logo,
617
- alt: "Company Logo",
618
- className: "logo-image"
619
- }
620
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "logo-text", children: config?.widget_config.company_logo }) : "\u{1F916}" }),
621
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
622
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "company-name", children: config?.widget_config.company_name }),
623
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "status-text", children: isLoading ? "Yaz\u0131yor..." : "\xC7evrimi\xE7i" })
850
+ /* @__PURE__ */ jsxRuntime.jsx(
851
+ "div",
852
+ {
853
+ className: `chat-container ${config?.widget_config.button_position} ${isOpen ? "is-open" : ""}`,
854
+ style: { width: config?.widget_config.chat_width, height: config?.widget_config.chat_height },
855
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatbot-container", children: [
856
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "header", style: { background: config?.widget_config.header_background }, children: [
857
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "logo-container", children: config?.widget_config.company_logo ? config?.widget_config.company_logo.startsWith("http") || config?.widget_config.company_logo.startsWith("data:") ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: config?.widget_config.company_logo, alt: "Company Logo", className: "logo-image" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "logo-text", children: config?.widget_config.company_logo }) : "\u{1F916}" }),
858
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
859
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "company-name", children: config?.widget_config.company_name }),
860
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "status-text", children: isLoading ? "Typing..." : "Online" })
861
+ ] })
862
+ ] }),
863
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chat-content", children: [
864
+ activeTab === "home" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-panel", children: [
865
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Welcome" }),
866
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "panel-title", children: config?.widget_config.company_name }),
867
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "panel-subtitle", children: "Ask anything. We keep your history and respond instantly." }),
868
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-actions", children: [
869
+ /* @__PURE__ */ jsxRuntime.jsx(
870
+ "button",
871
+ {
872
+ className: "primary-button",
873
+ onClick: async () => {
874
+ try {
875
+ await createNewSession();
876
+ } catch (e) {
877
+ console.error(e);
878
+ }
879
+ },
880
+ disabled: isLoading || sessions.length >= MAX_SESSIONS,
881
+ children: "Start a new conversation"
882
+ }
883
+ ),
884
+ /* @__PURE__ */ jsxRuntime.jsx(
885
+ "button",
886
+ {
887
+ className: "ghost-button",
888
+ onClick: () => {
889
+ setActiveTab("messages");
890
+ setMessageView("list");
891
+ },
892
+ children: "View conversations"
893
+ }
894
+ )
895
+ ] })
896
+ ] }),
897
+ activeTab === "messages" && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: messageView === "list" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-list", children: [
898
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "list-header", children: [
899
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
900
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Conversations" }),
901
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "panel-title", children: "Inbox" })
902
+ ] }),
903
+ /* @__PURE__ */ jsxRuntime.jsx(
904
+ "button",
905
+ {
906
+ className: "session-new-button",
907
+ onClick: async () => {
908
+ try {
909
+ await createNewSession();
910
+ } catch (e) {
911
+ console.error(e);
912
+ }
913
+ },
914
+ disabled: sessions.length >= MAX_SESSIONS,
915
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "+ New" })
916
+ }
917
+ )
918
+ ] }),
919
+ sessions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-list", children: [
920
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
921
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "empty-state-title", children: "No conversations yet" }),
922
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-description", children: "Start a new conversation to see it appear here." })
923
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "conversation-items", children: sessions.map((sid) => /* @__PURE__ */ jsxRuntime.jsxs(
924
+ "button",
925
+ {
926
+ className: `conversation-item ${sid === activeSessionId ? "active" : ""}`,
927
+ onClick: () => handleSelectSession(sid),
928
+ children: [
929
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-meta", children: [
930
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "conversation-title", children: getSessionLabel(sid) }),
931
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "conversation-sub", children: [
932
+ "Session ID: ",
933
+ sid.slice(0, 8),
934
+ "..."
935
+ ] })
936
+ ] }),
937
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "conversation-pill", children: "Open" })
938
+ ]
939
+ },
940
+ sid
941
+ )) })
942
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-detail", children: [
943
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header", children: [
944
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-header-left", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "icon-button", onClick: () => setMessageView("list"), "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
945
+ "path",
946
+ {
947
+ d: "M15 18l-6-6 6-6",
948
+ stroke: "currentColor",
949
+ strokeWidth: "2",
950
+ strokeLinecap: "round",
951
+ strokeLinejoin: "round"
952
+ }
953
+ ) }) }) }),
954
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-center", children: [
955
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
956
+ "path",
957
+ {
958
+ d: "M12 3c-4.418 0-8 3.134-8 7 0 2.382 1.362 4.486 3.5 5.737V21l4.07-2.13c.14.008.283.013.43.013 4.418 0 8-3.134 8-7s-3.582-7-8-7z",
959
+ stroke: "currentColor",
960
+ strokeWidth: "2",
961
+ strokeLinejoin: "round"
962
+ }
963
+ ) }) }),
964
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title", children: [
965
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title-row", children: [
966
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "detail-title-text", children: activeSessionId ? getSessionLabel(activeSessionId) : "Chat" }),
967
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `status-dot ${isLoading ? "typing" : "online"}`, "aria-hidden": "true" })
968
+ ] }),
969
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "detail-subtitle", children: isLoading ? "Yaz\u0131yor\u2026" : "Online" })
970
+ ] })
971
+ ] }),
972
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-right", children: [
973
+ /* @__PURE__ */ jsxRuntime.jsx(
974
+ "button",
975
+ {
976
+ className: "icon-button",
977
+ onClick: () => {
978
+ setActiveTab("info");
979
+ setMessageView("list");
980
+ },
981
+ "aria-label": "Bilgi",
982
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
983
+ /* @__PURE__ */ jsxRuntime.jsx(
984
+ "path",
985
+ {
986
+ d: "M12 17v-6",
987
+ stroke: "currentColor",
988
+ strokeWidth: "2",
989
+ strokeLinecap: "round"
990
+ }
991
+ ),
992
+ /* @__PURE__ */ jsxRuntime.jsx(
993
+ "path",
994
+ {
995
+ d: "M12 8h.01",
996
+ stroke: "currentColor",
997
+ strokeWidth: "2.5",
998
+ strokeLinecap: "round"
999
+ }
1000
+ ),
1001
+ /* @__PURE__ */ jsxRuntime.jsx(
1002
+ "circle",
1003
+ {
1004
+ cx: "12",
1005
+ cy: "12",
1006
+ r: "9",
1007
+ stroke: "currentColor",
1008
+ strokeWidth: "2"
1009
+ }
1010
+ )
1011
+ ] })
1012
+ }
1013
+ ),
1014
+ /* @__PURE__ */ jsxRuntime.jsx(
1015
+ "button",
1016
+ {
1017
+ className: "icon-button danger",
1018
+ onClick: disconnectActiveSession,
1019
+ disabled: !activeSessionId,
1020
+ "aria-label": "End conversation",
1021
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
1022
+ /* @__PURE__ */ jsxRuntime.jsx(
1023
+ "path",
1024
+ {
1025
+ d: "M3 6h18",
1026
+ stroke: "currentColor",
1027
+ strokeWidth: "2",
1028
+ strokeLinecap: "round"
1029
+ }
1030
+ ),
1031
+ /* @__PURE__ */ jsxRuntime.jsx(
1032
+ "path",
1033
+ {
1034
+ d: "M8 6V4h8v2",
1035
+ stroke: "currentColor",
1036
+ strokeWidth: "2",
1037
+ strokeLinejoin: "round"
1038
+ }
1039
+ ),
1040
+ /* @__PURE__ */ jsxRuntime.jsx(
1041
+ "path",
1042
+ {
1043
+ d: "M6 6l1 16h10l1-16",
1044
+ stroke: "currentColor",
1045
+ strokeWidth: "2",
1046
+ strokeLinejoin: "round"
1047
+ }
1048
+ )
1049
+ ] })
1050
+ }
1051
+ )
1052
+ ] })
1053
+ ] }),
1054
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "messages-container", children: [
1055
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderAlert, { headerValidation, setShowAlert, showAlert }),
1056
+ messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: clean } }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1057
+ messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { message, onAction: sendMessage }, index)),
1058
+ config?.widget_config.show_typing_indicator && isLoading && /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {})
1059
+ ] }),
1060
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
1061
+ ] }),
1062
+ /* @__PURE__ */ jsxRuntime.jsx(
1063
+ ChatInput,
1064
+ {
1065
+ handleSendMessage: sendMessage,
1066
+ isLoading,
1067
+ placeholder: config?.widget_config.placeholder ?? ""
1068
+ }
1069
+ )
1070
+ ] }) }),
1071
+ activeTab === "info" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "info-panel", children: [
1072
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Info" }),
1073
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "panel-title", children: "Widget Details" }),
1074
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "info-list", children: [
1075
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1076
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Company" }),
1077
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: config?.widget_config.company_name })
1078
+ ] }),
1079
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1080
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Status" }),
1081
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: isLoading ? "Typing..." : "Online" })
1082
+ ] }),
1083
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1084
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Conversations" }),
1085
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: sessions.length })
1086
+ ] })
1087
+ ] })
1088
+ ] })
1089
+ ] }),
1090
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bottom-nav", children: [
1091
+ /* @__PURE__ */ jsxRuntime.jsx(
1092
+ "button",
1093
+ {
1094
+ className: `nav-button ${activeTab === "home" ? "active" : ""}`,
1095
+ onClick: () => {
1096
+ setActiveTab("home");
1097
+ setMessageView("list");
1098
+ },
1099
+ children: "Home"
1100
+ }
1101
+ ),
1102
+ /* @__PURE__ */ jsxRuntime.jsx(
1103
+ "button",
1104
+ {
1105
+ className: `nav-button ${activeTab === "messages" ? "active" : ""}`,
1106
+ onClick: () => {
1107
+ setActiveTab("messages");
1108
+ setMessageView("list");
1109
+ },
1110
+ children: "Messages"
1111
+ }
1112
+ ),
1113
+ /* @__PURE__ */ jsxRuntime.jsx(
1114
+ "button",
1115
+ {
1116
+ className: `nav-button ${activeTab === "info" ? "active" : ""}`,
1117
+ onClick: () => {
1118
+ setActiveTab("info");
1119
+ setMessageView("list");
1120
+ },
1121
+ children: "Info"
1122
+ }
1123
+ )
1124
+ ] })
624
1125
  ] })
625
- ] }),
626
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "messages-container", children: [
627
- /* @__PURE__ */ jsxRuntime.jsx(
628
- HeaderAlert,
629
- {
630
- headerValidation,
631
- setShowAlert,
632
- showAlert
633
- }
634
- ),
635
- messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-state", children: [
636
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
637
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "empty-state-title", children: config?.widget_config.welcome_message }),
638
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-description", children: "A\u015Fa\u011F\u0131daki alana mesaj\u0131n\u0131z\u0131 yazarak ba\u015Flayabilirsiniz." })
639
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
640
- messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(
641
- MessageBubble,
642
- {
643
- message,
644
- onAction: sendMessage
645
- },
646
- index
647
- )),
648
- config?.widget_config.show_typing_indicator && isLoading && /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {})
649
- ] }),
650
- /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
651
- ] }),
652
- /* @__PURE__ */ jsxRuntime.jsx(
653
- ChatInput,
654
- {
655
- handleSendMessage: sendMessage,
656
- isLoading,
657
- placeholder: config?.widget_config.placeholder ?? ""
658
- }
659
- )
660
- ] }) }),
1126
+ }
1127
+ ),
661
1128
  /* @__PURE__ */ jsxRuntime.jsx(
662
1129
  "button",
663
1130
  {
664
1131
  onClick: toggleChat,
665
1132
  className: `floating-button ${config?.widget_config.button_position} button-sizes ${config?.widget_config.button_size} ${isOpen ? "is-open" : ""}`,
666
1133
  style: { background: config?.widget_config.button_background },
667
- "aria-label": isOpen ? "Chati kapat" : "Chati a\xE7",
668
- children: isOpen ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4l4 4 4-4h4c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z" }) })
1134
+ children: isOpen ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4l4 4 4-4h4c1.1 0-2 .9-2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z" }) })
669
1135
  }
670
1136
  )
671
1137
  ] }) });