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