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.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,77 +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);
543
+ const deviceId = getOrCreateDeviceId();
544
+ purgeExpiredLocalSessions(setActiveSessionIdState);
545
+ const localActive = getActiveSessionId();
438
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"
552
+ }
445
553
  });
446
554
  const data = await response.json();
447
- if (data.success) {
448
- setIsOpen(data.data.widget_config.initial_open);
449
- setConfig(data.data);
450
- if (headers) {
451
- const validationResult = validateHeaders(
452
- headers,
453
- data.data.auth_config,
454
- {
455
- allowExtra: false,
456
- caseSensitive: true
457
- }
458
- );
459
- setHeaderValidation(validationResult);
460
- }
461
- onReady?.({ config: { ...data.data } });
462
- } else {
555
+ if (!data.success) {
463
556
  setIsOpen(false);
557
+ return;
464
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);
579
+ }
580
+ onReady?.({ config: { ...data.data } });
465
581
  } catch (error) {
466
582
  console.error("Failed to load chat widget config:", error);
467
583
  } finally {
468
584
  setIsConfigLoading(false);
469
585
  }
470
586
  };
471
- const disconnect = async () => {
587
+ const getHistoryMessageBySessionId = async (sid) => {
472
588
  try {
473
- setIsConfigLoading(true);
474
- await fetch(`${PROXY_BASE_URL}/aizek-disconnect?clientId=${clientId}`, {
475
- method: "POST",
589
+ const deviceId = getOrCreateDeviceId();
590
+ const response = await fetch(`${PROXY_BASE_URL}/aizek-messages`, {
591
+ method: "GET",
476
592
  headers: {
477
593
  "Content-Type": "application/json",
594
+ "x-device-id": deviceId,
595
+ "x-session-id": sid,
478
596
  "x-alternate": JSON.stringify(headers)
479
- },
480
- credentials: "include"
597
+ }
481
598
  });
482
- 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;
483
635
  } catch (error) {
484
- console.error("Failed to load chat widget config:", error);
485
- } finally {
486
- setIsConfigLoading(false);
636
+ console.error("Error fetching message history:", error);
637
+ return [];
487
638
  }
488
639
  };
489
640
  useEffect(() => {
490
641
  onMounted?.();
491
642
  loadConfig();
492
- return () => {
493
- disconnect();
494
- };
495
643
  }, []);
496
644
  useEffect(() => {
497
- const newIsOpen = !isOpen;
498
- setIsOpen(newIsOpen);
499
- if (newIsOpen) onOpen?.();
500
- 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
+ }
501
657
  }, [config?.widget_config.initial_open]);
502
658
  useEffect(() => {
503
659
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
504
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]);
505
672
  const addMessage = (payload) => {
506
673
  const newMessage = {
507
674
  text: payload.text,
@@ -516,24 +683,51 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
516
683
  };
517
684
  const sendMessage = async (message, approval) => {
518
685
  if (!message.trim() || isLoading) return;
519
- const newMessage = {
520
- text: message,
521
- ui: void 0,
522
- role: approval ? "approval" : "user",
523
- timestamp: /* @__PURE__ */ new Date()
524
- };
525
- setMessages((prev) => [...prev, newMessage]);
686
+ setMessages((prev) => [
687
+ ...prev,
688
+ { text: message, ui: void 0, role: approval ? "approval" : "user", timestamp: /* @__PURE__ */ new Date() }
689
+ ]);
526
690
  setIsLoading(true);
527
691
  try {
692
+ const deviceId = getOrCreateDeviceId();
693
+ purgeExpiredLocalSessions(setActiveSessionIdState);
694
+ let sid = activeSessionId;
695
+ if (!sid) sid = await createNewSession();
528
696
  const response = await fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
529
697
  method: "POST",
530
698
  headers: {
531
699
  "Content-Type": "application/json",
700
+ "x-device-id": deviceId,
701
+ "x-session-id": sid,
532
702
  "x-alternate": JSON.stringify(headers)
533
703
  },
534
- body: JSON.stringify({ message }),
535
- credentials: "include"
704
+ body: JSON.stringify({ message })
536
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
+ }
537
731
  if (!response.ok) {
538
732
  throw new Error(`HTTP error ${response.status}`);
539
733
  }
@@ -577,87 +771,359 @@ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, on
577
771
  }
578
772
  }
579
773
  }
774
+ touchSession(sid);
580
775
  } catch (error) {
581
776
  console.error("Error sending message:", error);
582
- 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" });
583
778
  } finally {
584
779
  setIsLoading(false);
585
780
  }
586
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
+ };
587
820
  const toggleChat = () => {
588
821
  const newIsOpen = !isOpen;
589
822
  setIsOpen(newIsOpen);
590
823
  if (newIsOpen) onOpen?.();
591
824
  else onClose?.();
592
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
+ });
593
832
  return /* @__PURE__ */ jsx(Fragment, { children: isConfigLoading ? /* @__PURE__ */ jsx(
594
833
  "button",
595
834
  {
596
835
  className: "floating-button bottom-right button-sizes medium loading-state",
597
836
  style: { background: "#4f46e5" },
598
- "aria-label": "Y\xFCkleniyor",
837
+ "aria-label": "Loading",
599
838
  children: /* @__PURE__ */ jsx("div", { className: "loading-spinner" })
600
839
  }
601
840
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
602
841
  isOpen && /* @__PURE__ */ jsx("div", { className: `overlay floating-chat-overlay ${isOpen ? "is-open" : ""}`, onClick: toggleChat }),
603
- /* @__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: [
604
- /* @__PURE__ */ jsxs("div", { className: "header", style: { background: config?.widget_config.header_background }, children: [
605
- /* @__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(
606
- "img",
607
- {
608
- src: config?.widget_config.company_logo,
609
- alt: "Company Logo",
610
- className: "logo-image"
611
- }
612
- ) : /* @__PURE__ */ jsx("span", { className: "logo-text", children: config?.widget_config.company_logo }) : "\u{1F916}" }),
613
- /* @__PURE__ */ jsxs("div", { children: [
614
- /* @__PURE__ */ jsx("h3", { className: "company-name", children: config?.widget_config.company_name }),
615
- /* @__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
+ ] })
616
1117
  ] })
617
- ] }),
618
- /* @__PURE__ */ jsxs("div", { className: "messages-container", children: [
619
- /* @__PURE__ */ jsx(
620
- HeaderAlert,
621
- {
622
- headerValidation,
623
- setShowAlert,
624
- showAlert
625
- }
626
- ),
627
- messages.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "empty-state", children: [
628
- /* @__PURE__ */ jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
629
- /* @__PURE__ */ jsx("h4", { className: "empty-state-title", children: config?.widget_config.welcome_message }),
630
- /* @__PURE__ */ jsx("p", { className: "empty-state-description", children: "A\u015Fa\u011F\u0131daki alana mesaj\u0131n\u0131z\u0131 yazarak ba\u015Flayabilirsiniz." })
631
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
632
- messages.map((message, index) => /* @__PURE__ */ jsx(
633
- MessageBubble,
634
- {
635
- message,
636
- onAction: sendMessage
637
- },
638
- index
639
- )),
640
- config?.widget_config.show_typing_indicator && isLoading && /* @__PURE__ */ jsx(TypingDots, {})
641
- ] }),
642
- /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
643
- ] }),
644
- /* @__PURE__ */ jsx(
645
- ChatInput,
646
- {
647
- handleSendMessage: sendMessage,
648
- isLoading,
649
- placeholder: config?.widget_config.placeholder ?? ""
650
- }
651
- )
652
- ] }) }),
1118
+ }
1119
+ ),
653
1120
  /* @__PURE__ */ jsx(
654
1121
  "button",
655
1122
  {
656
1123
  onClick: toggleChat,
657
1124
  className: `floating-button ${config?.widget_config.button_position} button-sizes ${config?.widget_config.button_size} ${isOpen ? "is-open" : ""}`,
658
1125
  style: { background: config?.widget_config.button_background },
659
- "aria-label": isOpen ? "Chati kapat" : "Chati a\xE7",
660
- 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" }) })
661
1127
  }
662
1128
  )
663
1129
  ] }) });