aizek-chatbot 1.0.27 → 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,77 +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);
551
+ const deviceId = getOrCreateDeviceId();
552
+ purgeExpiredLocalSessions(setActiveSessionIdState);
553
+ const localActive = getActiveSessionId();
445
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"
560
+ }
452
561
  });
453
562
  const data = await response.json();
454
- if (data.success) {
455
- setIsOpen(data.data.widget_config.initial_open);
456
- setConfig(data.data);
457
- if (headers) {
458
- const validationResult = validateHeaders(
459
- headers,
460
- data.data.auth_config,
461
- {
462
- allowExtra: false,
463
- caseSensitive: true
464
- }
465
- );
466
- setHeaderValidation(validationResult);
467
- }
468
- onReady?.({ config: { ...data.data } });
469
- } else {
563
+ if (!data.success) {
470
564
  setIsOpen(false);
565
+ return;
471
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);
587
+ }
588
+ onReady?.({ config: { ...data.data } });
472
589
  } catch (error) {
473
590
  console.error("Failed to load chat widget config:", error);
474
591
  } finally {
475
592
  setIsConfigLoading(false);
476
593
  }
477
594
  };
478
- const disconnect = async () => {
595
+ const getHistoryMessageBySessionId = async (sid) => {
479
596
  try {
480
- setIsConfigLoading(true);
481
- await fetch(`${PROXY_BASE_URL}/aizek-disconnect?clientId=${clientId}`, {
482
- method: "POST",
597
+ const deviceId = getOrCreateDeviceId();
598
+ const response = await fetch(`${PROXY_BASE_URL}/aizek-messages`, {
599
+ method: "GET",
483
600
  headers: {
484
601
  "Content-Type": "application/json",
602
+ "x-device-id": deviceId,
603
+ "x-session-id": sid,
485
604
  "x-alternate": JSON.stringify(headers)
486
- },
487
- credentials: "include"
605
+ }
488
606
  });
489
- 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;
490
643
  } catch (error) {
491
- console.error("Failed to load chat widget config:", error);
492
- } finally {
493
- setIsConfigLoading(false);
644
+ console.error("Error fetching message history:", error);
645
+ return [];
494
646
  }
495
647
  };
496
648
  react.useEffect(() => {
497
649
  onMounted?.();
498
650
  loadConfig();
499
- return () => {
500
- disconnect();
501
- };
502
651
  }, []);
503
652
  react.useEffect(() => {
504
- const newIsOpen = !isOpen;
505
- setIsOpen(newIsOpen);
506
- if (newIsOpen) onOpen?.();
507
- 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
+ }
508
665
  }, [config?.widget_config.initial_open]);
509
666
  react.useEffect(() => {
510
667
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
511
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]);
512
680
  const addMessage = (payload) => {
513
681
  const newMessage = {
514
682
  text: payload.text,
@@ -523,24 +691,51 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
523
691
  };
524
692
  const sendMessage = async (message, approval) => {
525
693
  if (!message.trim() || isLoading) return;
526
- const newMessage = {
527
- text: message,
528
- ui: void 0,
529
- role: approval ? "approval" : "user",
530
- timestamp: /* @__PURE__ */ new Date()
531
- };
532
- setMessages((prev) => [...prev, newMessage]);
694
+ setMessages((prev) => [
695
+ ...prev,
696
+ { text: message, ui: void 0, role: approval ? "approval" : "user", timestamp: /* @__PURE__ */ new Date() }
697
+ ]);
533
698
  setIsLoading(true);
534
699
  try {
700
+ const deviceId = getOrCreateDeviceId();
701
+ purgeExpiredLocalSessions(setActiveSessionIdState);
702
+ let sid = activeSessionId;
703
+ if (!sid) sid = await createNewSession();
535
704
  const response = await fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
536
705
  method: "POST",
537
706
  headers: {
538
707
  "Content-Type": "application/json",
708
+ "x-device-id": deviceId,
709
+ "x-session-id": sid,
539
710
  "x-alternate": JSON.stringify(headers)
540
711
  },
541
- body: JSON.stringify({ message }),
542
- credentials: "include"
712
+ body: JSON.stringify({ message })
543
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
+ }
544
739
  if (!response.ok) {
545
740
  throw new Error(`HTTP error ${response.status}`);
546
741
  }
@@ -584,87 +779,359 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
584
779
  }
585
780
  }
586
781
  }
782
+ touchSession(sid);
587
783
  } catch (error) {
588
784
  console.error("Error sending message:", error);
589
- 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" });
590
786
  } finally {
591
787
  setIsLoading(false);
592
788
  }
593
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
+ };
594
828
  const toggleChat = () => {
595
829
  const newIsOpen = !isOpen;
596
830
  setIsOpen(newIsOpen);
597
831
  if (newIsOpen) onOpen?.();
598
832
  else onClose?.();
599
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
+ });
600
840
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: isConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx(
601
841
  "button",
602
842
  {
603
843
  className: "floating-button bottom-right button-sizes medium loading-state",
604
844
  style: { background: "#4f46e5" },
605
- "aria-label": "Y\xFCkleniyor",
845
+ "aria-label": "Loading",
606
846
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loading-spinner" })
607
847
  }
608
848
  ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
609
849
  isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `overlay floating-chat-overlay ${isOpen ? "is-open" : ""}`, onClick: toggleChat }),
610
- /* @__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: [
611
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "header", style: { background: config?.widget_config.header_background }, children: [
612
- /* @__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(
613
- "img",
614
- {
615
- src: config?.widget_config.company_logo,
616
- alt: "Company Logo",
617
- className: "logo-image"
618
- }
619
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "logo-text", children: config?.widget_config.company_logo }) : "\u{1F916}" }),
620
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
621
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "company-name", children: config?.widget_config.company_name }),
622
- /* @__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
+ ] })
623
1125
  ] })
624
- ] }),
625
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "messages-container", children: [
626
- /* @__PURE__ */ jsxRuntime.jsx(
627
- HeaderAlert,
628
- {
629
- headerValidation,
630
- setShowAlert,
631
- showAlert
632
- }
633
- ),
634
- messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-state", children: [
635
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
636
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "empty-state-title", children: config?.widget_config.welcome_message }),
637
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-description", children: "A\u015Fa\u011F\u0131daki alana mesaj\u0131n\u0131z\u0131 yazarak ba\u015Flayabilirsiniz." })
638
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
639
- messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(
640
- MessageBubble,
641
- {
642
- message,
643
- onAction: sendMessage
644
- },
645
- index
646
- )),
647
- config?.widget_config.show_typing_indicator && isLoading && /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {})
648
- ] }),
649
- /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
650
- ] }),
651
- /* @__PURE__ */ jsxRuntime.jsx(
652
- ChatInput,
653
- {
654
- handleSendMessage: sendMessage,
655
- isLoading,
656
- placeholder: config?.widget_config.placeholder ?? ""
657
- }
658
- )
659
- ] }) }),
1126
+ }
1127
+ ),
660
1128
  /* @__PURE__ */ jsxRuntime.jsx(
661
1129
  "button",
662
1130
  {
663
1131
  onClick: toggleChat,
664
1132
  className: `floating-button ${config?.widget_config.button_position} button-sizes ${config?.widget_config.button_size} ${isOpen ? "is-open" : ""}`,
665
1133
  style: { background: config?.widget_config.button_background },
666
- "aria-label": isOpen ? "Chati kapat" : "Chati a\xE7",
667
- 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" }) })
668
1135
  }
669
1136
  )
670
1137
  ] }) });