aizek-chatbot 1.0.26 → 1.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +568 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +475 -2
- package/dist/index.css.map +1 -1
- package/dist/index.mjs +567 -102
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
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/
|
|
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 = ({
|
|
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
|
|
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
|
|
587
|
+
const getHistoryMessageBySessionId = async (sid) => {
|
|
473
588
|
try {
|
|
474
|
-
|
|
475
|
-
await fetch(`${PROXY_BASE_URL}/aizek-
|
|
476
|
-
method: "
|
|
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
|
-
|
|
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("
|
|
486
|
-
|
|
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
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
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
|
-
|
|
521
|
-
|
|
522
|
-
ui: void 0,
|
|
523
|
-
|
|
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
|
|
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: "
|
|
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": "
|
|
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(
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
className: "logo-image"
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
] }) });
|