aizek-chatbot 1.0.29 → 1.0.30

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 ADDED
@@ -0,0 +1,1190 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var ReactMarkdown = require('react-markdown');
6
+ var remarkGfm = require('remark-gfm');
7
+ var sanitizeHtml = require('sanitize-html');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
12
+ var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
13
+ var sanitizeHtml__default = /*#__PURE__*/_interopDefault(sanitizeHtml);
14
+
15
+ // src/utils/global.ts
16
+ var SESSION_TTL_MS = 60 * 60 * 1e3;
17
+ var MAX_SESSIONS = 3;
18
+ var DEVICE_KEY = "aizek_device_id_v1";
19
+ var ACTIVE_SESSION_KEY = "aizek_active_session_v1";
20
+ var LOCAL_SESSIONS_KEY = "aizek_sessions_v1";
21
+ function validateHeaders(headers, authConfig, opts = {}) {
22
+ if (headers && (!authConfig || Object.keys(authConfig).length === 0)) {
23
+ return {
24
+ isValid: false,
25
+ missingKeys: [],
26
+ extraKeys: [],
27
+ emptyValueKeys: [],
28
+ warning: "Auth config bo\u015F ya da tan\u0131ms\u0131z, header do\u011Frulamas\u0131 yap\u0131lam\u0131yor."
29
+ };
30
+ }
31
+ const { caseSensitive = false, allowExtra = false } = opts;
32
+ const normalize = (s) => caseSensitive ? s : s.toLowerCase();
33
+ const headerEntries = Object.entries(headers).map(([k, v]) => [normalize(k), v.trim()]);
34
+ const authEntries = Object.entries(authConfig).map(([k, v]) => [normalize(k), v.trim()]);
35
+ const headerKeys = headerEntries.map(([k]) => k);
36
+ const authKeys = authEntries.map(([k]) => k);
37
+ const requiredSet = new Set(authKeys);
38
+ const missingKeys = authKeys.filter((k) => !headerKeys.includes(k));
39
+ const extraKeys = headerKeys.filter((k) => !requiredSet.has(k));
40
+ const hasAllRequired = missingKeys.length === 0;
41
+ const hasExtraKeys = extraKeys.length > 0 && !allowExtra;
42
+ const emptyValueKeys = authKeys.filter((k) => {
43
+ const val = headerEntries.find(([key]) => key === k)?.[1];
44
+ return !val || val.length === 0;
45
+ });
46
+ const isValid = hasAllRequired && !hasExtraKeys && emptyValueKeys.length === 0;
47
+ return { isValid, missingKeys, extraKeys, emptyValueKeys };
48
+ }
49
+ function getOrCreateDeviceId() {
50
+ if (typeof window === "undefined") return "";
51
+ const existing = localStorage.getItem(DEVICE_KEY);
52
+ if (existing) return existing;
53
+ const id = crypto.randomUUID();
54
+ localStorage.setItem(DEVICE_KEY, id);
55
+ return id;
56
+ }
57
+ function now() {
58
+ return Date.now();
59
+ }
60
+ function readStoredSessions() {
61
+ try {
62
+ const raw = localStorage.getItem(LOCAL_SESSIONS_KEY);
63
+ const parsed = JSON.parse(raw ?? "[]");
64
+ if (!Array.isArray(parsed)) return [];
65
+ return parsed.filter((x) => x && typeof x.sessionId === "string" && typeof x.lastActive === "number").slice(0, MAX_SESSIONS);
66
+ } catch {
67
+ return [];
68
+ }
69
+ }
70
+ function writeStoredSessions(list) {
71
+ localStorage.setItem(LOCAL_SESSIONS_KEY, JSON.stringify(list.slice(0, MAX_SESSIONS)));
72
+ }
73
+ function purgeExpiredLocalSessions(setActiveSessionIdState) {
74
+ const list = readStoredSessions();
75
+ const filtered = list.filter((s) => now() - s.lastActive <= SESSION_TTL_MS);
76
+ if (filtered.length !== list.length) writeStoredSessions(filtered);
77
+ const active = getActiveSessionId();
78
+ if (active && !filtered.some((s) => s.sessionId === active)) {
79
+ setActiveSessionId(null);
80
+ setActiveSessionIdState(null);
81
+ }
82
+ return filtered;
83
+ }
84
+ function getActiveSessionId() {
85
+ return localStorage.getItem(ACTIVE_SESSION_KEY);
86
+ }
87
+ function setActiveSessionId(id) {
88
+ if (!id) localStorage.removeItem(ACTIVE_SESSION_KEY);
89
+ else localStorage.setItem(ACTIVE_SESSION_KEY, id);
90
+ }
91
+ function touchSession(sessionId) {
92
+ const list = readStoredSessions();
93
+ const next = list.map((s) => s.sessionId === sessionId ? { ...s, lastActive: now() } : s);
94
+ if (!next.some((s) => s.sessionId === sessionId)) next.unshift({ sessionId, lastActive: now() });
95
+ writeStoredSessions(next.slice(0, MAX_SESSIONS));
96
+ }
97
+ function upsertSessionsFromServer(serverSessionIds, setSessions) {
98
+ const local = readStoredSessions();
99
+ const map = new Map(local.map((s) => [s.sessionId, s.lastActive]));
100
+ const merged = serverSessionIds.slice(0, MAX_SESSIONS).map((sid) => ({
101
+ sessionId: sid,
102
+ lastActive: map.get(sid) ?? now()
103
+ }));
104
+ writeStoredSessions(merged);
105
+ setSessions(merged.map((x) => x.sessionId));
106
+ return merged;
107
+ }
108
+ var HeaderAlert = ({ headerValidation, showAlert, setShowAlert }) => {
109
+ if (!headerValidation || !showAlert) return null;
110
+ const { isValid, missingKeys, extraKeys, emptyValueKeys, warning } = headerValidation;
111
+ if (isValid && missingKeys.length === 0 && extraKeys.length === 0 && emptyValueKeys.length === 0 && !warning) {
112
+ return null;
113
+ }
114
+ const hasErrors = missingKeys.length > 0 || emptyValueKeys.length > 0;
115
+ const hasWarnings = extraKeys.length > 0 || !!warning;
116
+ const alertType = hasErrors ? "error" : "warning";
117
+ const getAlertIcon = () => {
118
+ if (hasErrors) {
119
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" }) });
120
+ }
121
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" }) });
122
+ };
123
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `alert-container ${alertType}`, children: [
124
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "alert-icon-container", children: getAlertIcon() }),
125
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "alert-content", children: [
126
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "alert-title", children: hasErrors ? "Header Do\u011Frulama Hatas\u0131" : "Header Uyar\u0131s\u0131" }),
127
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "alert-message", children: hasErrors && hasWarnings ? "Header yap\u0131land\u0131rman\u0131zda hatalar ve uyar\u0131lar bulundu." : hasErrors ? "Header yap\u0131land\u0131rman\u0131zda hatalar bulundu." : "Header yap\u0131land\u0131rman\u0131zda fazla anahtarlar bulundu." }),
128
+ missingKeys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
129
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Eksik Header'lar:" }),
130
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "alert-list", children: missingKeys.map((key, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "alert-list-item", children: [
131
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2022" }),
132
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: key })
133
+ ] }, index)) })
134
+ ] }),
135
+ emptyValueKeys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
136
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Bo\u015F De\u011Ferli Header'lar:" }),
137
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "alert-list", children: emptyValueKeys.map((key, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "alert-list-item", children: [
138
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2022" }),
139
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: key }),
140
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "(de\u011Fer bo\u015F olamaz)" })
141
+ ] }, index)) })
142
+ ] }),
143
+ extraKeys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
144
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Fazla Header'lar:" }),
145
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "alert-list", children: extraKeys.map((key, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "alert-list-item", children: [
146
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2022" }),
147
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: key })
148
+ ] }, index)) })
149
+ ] }),
150
+ warning && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
151
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Uyar\u0131:" }),
152
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "alert-message", children: warning })
153
+ ] })
154
+ ] }),
155
+ /* @__PURE__ */ jsxRuntime.jsx(
156
+ "button",
157
+ {
158
+ onClick: () => setShowAlert(false),
159
+ className: "alert-close-button",
160
+ "aria-label": "Uyar\u0131y\u0131 kapat",
161
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) })
162
+ }
163
+ )
164
+ ] }) });
165
+ };
166
+ var LoadingSpinner = () => {
167
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loading-spinner" });
168
+ };
169
+ var ChatInput = ({ isLoading, placeholder, handleSendMessage }) => {
170
+ const [message, setMessage] = react.useState("");
171
+ const textareaRef = react.useRef(null);
172
+ const handleSubmit = (e) => {
173
+ e.preventDefault();
174
+ if (message.trim() && !isLoading) {
175
+ handleSendMessage(message.trim());
176
+ setMessage("");
177
+ if (textareaRef.current) {
178
+ textareaRef.current.style.height = "auto";
179
+ }
180
+ }
181
+ };
182
+ const handleKeyDown = (e) => {
183
+ if (e.key === "Enter" && !e.shiftKey) {
184
+ e.preventDefault();
185
+ handleSubmit(e);
186
+ }
187
+ };
188
+ const handleInputChange = (e) => {
189
+ setMessage(e.target.value);
190
+ const textarea = e.target;
191
+ textarea.style.height = "auto";
192
+ textarea.style.height = Math.min(textarea.scrollHeight, 120) + "px";
193
+ };
194
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "input-container", children: [
195
+ /* @__PURE__ */ jsxRuntime.jsx(
196
+ "textarea",
197
+ {
198
+ ref: textareaRef,
199
+ value: message,
200
+ onChange: handleInputChange,
201
+ onKeyDown: handleKeyDown,
202
+ placeholder,
203
+ disabled: isLoading,
204
+ className: "textarea"
205
+ }
206
+ ),
207
+ /* @__PURE__ */ jsxRuntime.jsx(
208
+ "button",
209
+ {
210
+ type: "submit",
211
+ disabled: isLoading || !message.trim(),
212
+ className: "send-button",
213
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, {}) : /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" }) })
214
+ }
215
+ )
216
+ ] });
217
+ };
218
+ var GenericUIRenderer = ({ uiData, onInteraction }) => {
219
+ const containerRef = react.useRef(null);
220
+ if (!uiData || !uiData.components) return null;
221
+ const collectFormValues = () => {
222
+ if (!containerRef.current) return {};
223
+ const formData = {};
224
+ const inputs = containerRef.current.querySelectorAll("input, textarea, select");
225
+ inputs.forEach((element) => {
226
+ const name = element.getAttribute("name");
227
+ if (name) {
228
+ if (element instanceof HTMLInputElement && element.type === "checkbox") {
229
+ formData[name] = element.checked;
230
+ } else if (element instanceof HTMLInputElement && element.type === "radio") {
231
+ if (element.checked) {
232
+ formData[name] = element.value;
233
+ }
234
+ } else {
235
+ formData[name] = element.value;
236
+ }
237
+ }
238
+ });
239
+ return formData;
240
+ };
241
+ const renderComponent = (comp) => {
242
+ switch (comp.type) {
243
+ case "text":
244
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "gen-ui-text", children: comp.value ?? comp.label }, comp.id);
245
+ case "input":
246
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gen-ui-input-wrapper", children: [
247
+ comp.label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "gen-ui-input-label", children: comp.label }),
248
+ comp.fieldType === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
249
+ "textarea",
250
+ {
251
+ name: comp.id,
252
+ placeholder: comp.placeholder,
253
+ className: "gen-ui-textarea"
254
+ }
255
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
256
+ "input",
257
+ {
258
+ name: comp.id,
259
+ type: comp.fieldType || "text",
260
+ placeholder: comp.placeholder,
261
+ className: "gen-ui-input"
262
+ }
263
+ )
264
+ ] }, comp.id);
265
+ case "select":
266
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gen-ui-select-wrapper", children: [
267
+ comp.label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "gen-ui-select-label", children: comp.label }),
268
+ /* @__PURE__ */ jsxRuntime.jsx("select", { name: comp.id, className: "gen-ui-select", children: comp.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: opt }, opt)) })
269
+ ] }, comp.id);
270
+ case "button":
271
+ return /* @__PURE__ */ jsxRuntime.jsx(
272
+ "button",
273
+ {
274
+ onClick: () => {
275
+ const formValues = collectFormValues();
276
+ onInteraction({
277
+ action: comp.label,
278
+ buttonId: comp.buttonType,
279
+ formData: formValues
280
+ });
281
+ },
282
+ className: "gen-ui-button",
283
+ children: comp.label
284
+ },
285
+ comp.id
286
+ );
287
+ case "card":
288
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "gen-ui-card", children: [
289
+ comp.label && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "gen-ui-card-title", children: comp.label }),
290
+ comp.value && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "gen-ui-card-content", children: comp.value })
291
+ ] }, comp.id);
292
+ case "list":
293
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "gen-ui-list", children: comp.items?.map((item) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "gen-ui-list-item", children: item.label ?? String(item.value ?? "") }, item.id)) }, comp.id);
294
+ case "image":
295
+ return /* @__PURE__ */ jsxRuntime.jsx(
296
+ "img",
297
+ {
298
+ src: comp.url,
299
+ alt: comp.label || "",
300
+ className: "gen-ui-image"
301
+ },
302
+ comp.id
303
+ );
304
+ case "link":
305
+ return /* @__PURE__ */ jsxRuntime.jsx(
306
+ "a",
307
+ {
308
+ href: comp.url,
309
+ className: "gen-ui-link",
310
+ children: comp.label || comp.url
311
+ },
312
+ comp.id
313
+ );
314
+ case "table":
315
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "gen-ui-table-wrapper", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "gen-ui-table", children: [
316
+ comp.columns && /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "gen-ui-table-header", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: comp.columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "gen-ui-table-th", children: col }, col)) }) }),
317
+ comp.rows && /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "gen-ui-table-body", children: comp.rows.map((row, ridx) => /* @__PURE__ */ jsxRuntime.jsx("tr", { children: row.map((cell, cidx) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "gen-ui-table-td", children: cell }, cidx)) }, ridx)) })
318
+ ] }) }, comp.id);
319
+ case "form":
320
+ return /* @__PURE__ */ jsxRuntime.jsx("form", { className: "gen-ui-form", children: comp.items?.map((field) => renderComponent(field)) }, comp.id);
321
+ default:
322
+ return null;
323
+ }
324
+ };
325
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "generative-ui-container", ref: containerRef, children: [
326
+ (uiData.title || uiData.description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "generative-ui-header", children: [
327
+ uiData.title && /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "generative-ui-title", children: uiData.title }),
328
+ uiData.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "generative-ui-description", children: uiData.description })
329
+ ] }),
330
+ uiData.components.map((comp) => renderComponent(comp))
331
+ ] });
332
+ };
333
+ var MessageBubble = ({ message, onAction }) => {
334
+ console.log("MESSAGE", message);
335
+ const isUser = message.role === "user";
336
+ const approval = message.role === "approval";
337
+ if (approval) {
338
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
339
+ }
340
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `message-container ${isUser ? "user" : "assistant"}`, children: [
341
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `message-bubble ${isUser ? "user" : "assistant"}`, children: isUser ? message.text && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "markdown-content", children: message.text }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
342
+ message.text && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "markdown-content", children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown__default.default, { remarkPlugins: [remarkGfm__default.default], children: message.text }) }),
343
+ message.ui && /* @__PURE__ */ jsxRuntime.jsx(
344
+ GenericUIRenderer,
345
+ {
346
+ uiData: message.ui,
347
+ onInteraction: (event) => {
348
+ console.log("event", event);
349
+ if (event.buttonId === "submit") {
350
+ onAction(JSON.stringify(event.formData), true);
351
+ } else {
352
+ onAction(event.action, true);
353
+ }
354
+ }
355
+ }
356
+ )
357
+ ] }) }),
358
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `message-time ${isUser ? "user" : "assistant"}`, children: message.timestamp.toLocaleTimeString("tr-TR", {
359
+ hour: "2-digit",
360
+ minute: "2-digit"
361
+ }) })
362
+ ] });
363
+ };
364
+ var TypingDots = () => {
365
+ const [dots, setDots] = react.useState("");
366
+ react.useEffect(() => {
367
+ const interval = setInterval(() => {
368
+ setDots((prev) => {
369
+ if (prev === "...") return "";
370
+ return prev + ".";
371
+ });
372
+ }, 500);
373
+ return () => clearInterval(interval);
374
+ }, []);
375
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "message-container assistant", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "message-bubble assistant", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "message-typing-indicator", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: dots }) }) }) });
376
+ };
377
+
378
+ // src/utils/chatbot.ts
379
+ var extractUIJsonFromText = (text) => {
380
+ const regex = /```ui-component([\s\S]*?)```/g;
381
+ let cleaned = text;
382
+ let match;
383
+ let uiData = null;
384
+ while ((match = regex.exec(text)) !== null) {
385
+ const block = match[1].trim();
386
+ try {
387
+ const parsed = JSON.parse(block);
388
+ if (parsed && parsed.components && Array.isArray(parsed.components)) {
389
+ parsed.components = parsed.components.map((comp, index) => {
390
+ if (!comp.id || typeof comp.id !== "string" || !comp.id.trim()) {
391
+ comp.id = `ui-comp-${index}-${Date.now()}`;
392
+ }
393
+ if (comp.type === "button") {
394
+ if (!comp.buttonType) {
395
+ comp.buttonType = "click";
396
+ }
397
+ }
398
+ if (comp.type === "input") {
399
+ if (!comp.fieldType) {
400
+ comp.fieldType = "text";
401
+ }
402
+ }
403
+ if (comp.type === "select") {
404
+ if (comp.options && Array.isArray(comp.options)) {
405
+ const firstOption = comp.options[0];
406
+ if (typeof firstOption === "object" && firstOption !== null) {
407
+ if ("label" in firstOption || "value" in firstOption) {
408
+ comp.options = comp.options.map(
409
+ (opt) => opt.label || opt.value || String(opt)
410
+ );
411
+ }
412
+ }
413
+ }
414
+ }
415
+ if (comp.type === "table") {
416
+ if (comp.columns && Array.isArray(comp.columns)) {
417
+ const firstCol = comp.columns[0];
418
+ if (typeof firstCol === "object" && firstCol !== null) {
419
+ comp.columns = comp.columns.map(
420
+ (col) => col.label || col.id || String(col)
421
+ );
422
+ }
423
+ }
424
+ if (comp.rows && Array.isArray(comp.rows)) {
425
+ const firstRow = comp.rows[0];
426
+ if (typeof firstRow === "object" && !Array.isArray(firstRow)) {
427
+ comp.rows = comp.rows.map((row) => {
428
+ if (Array.isArray(row)) return row;
429
+ return Object.values(row).map((val) => {
430
+ if (typeof val === "object" && val !== null) {
431
+ if (val.type === "image" && val.src) return val.src;
432
+ if (val.value !== void 0) return String(val.value);
433
+ }
434
+ return String(val || "");
435
+ });
436
+ });
437
+ }
438
+ }
439
+ }
440
+ if (comp.type === "form" && comp.items && Array.isArray(comp.items)) {
441
+ comp.items = comp.items.map((field, fieldIndex) => {
442
+ if (!field.id || !field.id.trim()) {
443
+ field.id = `field-${fieldIndex}-${Date.now()}`;
444
+ }
445
+ if (field.optional !== void 0) {
446
+ field.requiredField = !field.optional;
447
+ delete field.optional;
448
+ }
449
+ if (field.required !== void 0) {
450
+ field.requiredField = field.required;
451
+ delete field.required;
452
+ }
453
+ if (field.type === "input" && !field.fieldType) {
454
+ field.fieldType = "text";
455
+ }
456
+ if (field.type === "select" && field.options && Array.isArray(field.options)) {
457
+ const firstOpt = field.options[0];
458
+ if (typeof firstOpt === "object" && firstOpt !== null) {
459
+ field.options = field.options.map(
460
+ (opt) => opt.label || opt.value || String(opt)
461
+ );
462
+ }
463
+ }
464
+ return field;
465
+ });
466
+ }
467
+ if (comp.type === "list" && comp.items && Array.isArray(comp.items)) {
468
+ comp.items = comp.items.map((item, itemIndex) => {
469
+ if (typeof item === "string") {
470
+ return {
471
+ id: `list-item-${itemIndex}-${Date.now()}`,
472
+ type: "text",
473
+ value: item,
474
+ label: item
475
+ };
476
+ }
477
+ if (!item.id || !item.id.trim()) {
478
+ item.id = `list-item-${itemIndex}-${Date.now()}`;
479
+ }
480
+ return item;
481
+ });
482
+ }
483
+ return comp;
484
+ });
485
+ uiData = parsed;
486
+ }
487
+ cleaned = cleaned.replace(match[0], "").trim();
488
+ break;
489
+ } catch (e) {
490
+ console.error("Invalid ui-component JSON:", e, block);
491
+ }
492
+ }
493
+ return {
494
+ cleanedText: cleaned,
495
+ uiData
496
+ };
497
+ };
498
+ var AizekChatBot = ({ clientId, headers, onMounted, onReady, onOpen, onClose, onMessage, onToolCall, onDisconnect }) => {
499
+ const messagesEndRef = react.useRef(null);
500
+ const [config, setConfig] = react.useState();
501
+ const [messages, setMessages] = react.useState([]);
502
+ const [isLoading, setIsLoading] = react.useState(false);
503
+ const [isConfigLoading, setIsConfigLoading] = react.useState(true);
504
+ const [isOpen, setIsOpen] = react.useState(false);
505
+ const [headerValidation, setHeaderValidation] = react.useState(null);
506
+ const [showAlert, setShowAlert] = react.useState(true);
507
+ const [sessions, setSessions] = react.useState([]);
508
+ const [activeSessionId, setActiveSessionIdState] = react.useState(null);
509
+ const [activeTab, setActiveTab] = react.useState("home");
510
+ const [messageView, setMessageView] = react.useState("list");
511
+ const [sessionTitleById, setSessionTitleById] = react.useState({});
512
+ const PROXY_BASE_URL = "https://proxy.aizek.ai/api";
513
+ const createNewSession = async () => {
514
+ const deviceId = getOrCreateDeviceId();
515
+ if (sessions.length >= MAX_SESSIONS) {
516
+ throw new Error(`You can open up to ${MAX_SESSIONS} sessions.`);
517
+ }
518
+ const res = await fetch(`${PROXY_BASE_URL}/aizek-sessions/new?clientId=${clientId}`, {
519
+ method: "POST",
520
+ headers: {
521
+ "Content-Type": "application/json",
522
+ "x-device-id": deviceId,
523
+ "x-alternate": JSON.stringify(headers)
524
+ }
525
+ });
526
+ const data = await res.json();
527
+ if (!data.success) throw new Error(data.message || "session create failed");
528
+ const sid = data.data.sessionId;
529
+ const updatedSessions = data.data.sessions ?? [sid];
530
+ upsertSessionsFromServer(updatedSessions, setSessions);
531
+ setActiveSessionIdState(sid);
532
+ setActiveSessionId(sid);
533
+ setActiveTab("messages");
534
+ setMessageView("detail");
535
+ touchSession(sid);
536
+ setMessages([]);
537
+ return sid;
538
+ };
539
+ const loadConfig = async () => {
540
+ try {
541
+ setIsConfigLoading(true);
542
+ const deviceId = getOrCreateDeviceId();
543
+ purgeExpiredLocalSessions(setActiveSessionIdState);
544
+ const localActive = getActiveSessionId();
545
+ const response = await fetch(`${PROXY_BASE_URL}/aizek-connect?clientId=${clientId}`, {
546
+ method: "POST",
547
+ headers: {
548
+ "Content-Type": "application/json",
549
+ "x-device-id": deviceId,
550
+ "x-alternate": JSON.stringify(headers)
551
+ }
552
+ });
553
+ const data = await response.json();
554
+ if (!data.success) {
555
+ setIsOpen(false);
556
+ return;
557
+ }
558
+ setIsOpen(!!data.data.widget_config.initial_open);
559
+ setConfig(data.data);
560
+ const serverSessions = data.data.sessions ?? [];
561
+ const merged = upsertSessionsFromServer(serverSessions, setSessions);
562
+ if (merged.length === 0) {
563
+ const newSid = await createNewSession();
564
+ setActiveSessionIdState(newSid);
565
+ setActiveSessionId(newSid);
566
+ return;
567
+ }
568
+ const mergedIds = merged.map((s) => s.sessionId);
569
+ const nextActive = (localActive && mergedIds.includes(localActive) ? localActive : null) ?? mergedIds[0] ?? null;
570
+ setActiveSessionIdState(nextActive);
571
+ setActiveSessionId(nextActive);
572
+ if (headers) {
573
+ const validationResult = validateHeaders(headers, data.data.auth_config, {
574
+ allowExtra: false,
575
+ caseSensitive: true
576
+ });
577
+ setHeaderValidation(validationResult);
578
+ }
579
+ onReady?.({ config: { ...data.data } });
580
+ } catch (error) {
581
+ console.error("Failed to load chat widget config:", error);
582
+ } finally {
583
+ setIsConfigLoading(false);
584
+ }
585
+ };
586
+ const getHistoryMessageBySessionId = async (sid) => {
587
+ try {
588
+ const deviceId = getOrCreateDeviceId();
589
+ const response = await fetch(`${PROXY_BASE_URL}/aizek-messages`, {
590
+ method: "GET",
591
+ headers: {
592
+ "Content-Type": "application/json",
593
+ "x-device-id": deviceId,
594
+ "x-session-id": sid,
595
+ "x-alternate": JSON.stringify(headers)
596
+ }
597
+ });
598
+ const data = await response.json();
599
+ if (!data.success) {
600
+ throw new Error(data.message || "Failed to fetch messages");
601
+ }
602
+ const historyMessages = [];
603
+ if (data.data?.messages && Array.isArray(data.data.messages)) {
604
+ for (const msg of data.data.messages) {
605
+ let textContent = "";
606
+ let uiData = null;
607
+ if (typeof msg.content === "string") {
608
+ textContent = msg.content;
609
+ } else if (Array.isArray(msg.content)) {
610
+ const textParts = [];
611
+ for (const item of msg.content) {
612
+ if (item.type === "text" && item.text) {
613
+ textParts.push(item.text);
614
+ }
615
+ }
616
+ textContent = textParts.join("\n");
617
+ }
618
+ if (textContent) {
619
+ const extracted = extractUIJsonFromText(textContent);
620
+ textContent = extracted.cleanedText;
621
+ uiData = extracted.uiData;
622
+ }
623
+ if (textContent.trim() || uiData) {
624
+ historyMessages.push({
625
+ text: textContent.trim() || void 0,
626
+ ui: uiData,
627
+ role: msg.role === "user" ? "user" : msg.role === "assistant" ? "assistant" : "user",
628
+ timestamp: /* @__PURE__ */ new Date()
629
+ });
630
+ }
631
+ }
632
+ }
633
+ return historyMessages;
634
+ } catch (error) {
635
+ console.error("Error fetching message history:", error);
636
+ return [];
637
+ }
638
+ };
639
+ react.useEffect(() => {
640
+ onMounted?.();
641
+ loadConfig();
642
+ }, []);
643
+ react.useEffect(() => {
644
+ const t = setInterval(() => {
645
+ purgeExpiredLocalSessions(setActiveSessionIdState);
646
+ }, 1e3);
647
+ return () => clearInterval(t);
648
+ }, []);
649
+ react.useEffect(() => {
650
+ if (typeof config?.widget_config.initial_open === "boolean") {
651
+ const open = config.widget_config.initial_open;
652
+ setIsOpen(open);
653
+ if (open) onOpen?.();
654
+ else onClose?.();
655
+ }
656
+ }, [config?.widget_config.initial_open]);
657
+ react.useEffect(() => {
658
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
659
+ }, [messages]);
660
+ react.useEffect(() => {
661
+ if (activeSessionId && !isConfigLoading) {
662
+ getHistoryMessageBySessionId(activeSessionId).then((historyMessages) => {
663
+ setMessages(historyMessages);
664
+ }).catch((error) => {
665
+ console.error("Failed to load message history:", error);
666
+ });
667
+ } else if (!activeSessionId) {
668
+ setMessages([]);
669
+ }
670
+ }, [activeSessionId, isConfigLoading]);
671
+ react.useEffect(() => {
672
+ if (!sessions.length) return;
673
+ const missing = sessions.filter((sid) => !sessionTitleById[sid]);
674
+ if (!missing.length) return;
675
+ let cancelled = false;
676
+ (async () => {
677
+ for (const sid of missing) {
678
+ if (cancelled) return;
679
+ const title = await fetchLastMessageTitle(sid);
680
+ if (cancelled) return;
681
+ if (!title) continue;
682
+ setSessionTitleById((prev) => prev[sid] ? prev : { ...prev, [sid]: title });
683
+ }
684
+ })();
685
+ return () => {
686
+ cancelled = true;
687
+ };
688
+ }, [sessions]);
689
+ const addMessage = (payload) => {
690
+ const newMessage = {
691
+ text: payload.text,
692
+ ui: payload.ui,
693
+ role: payload.role,
694
+ timestamp: /* @__PURE__ */ new Date()
695
+ };
696
+ onMessage?.(newMessage);
697
+ setMessages((prev) => [...prev, newMessage]);
698
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
699
+ return newMessage;
700
+ };
701
+ const sendMessage = async (message, approval) => {
702
+ if (!message.trim() || isLoading) return;
703
+ setMessages((prev) => [
704
+ ...prev,
705
+ { text: message, ui: void 0, role: approval ? "approval" : "user", timestamp: /* @__PURE__ */ new Date() }
706
+ ]);
707
+ setIsLoading(true);
708
+ try {
709
+ const deviceId = getOrCreateDeviceId();
710
+ purgeExpiredLocalSessions(setActiveSessionIdState);
711
+ let sid = activeSessionId;
712
+ if (!sid) sid = await createNewSession();
713
+ const response = 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": sid,
719
+ "x-alternate": JSON.stringify(headers)
720
+ },
721
+ body: JSON.stringify({ message })
722
+ });
723
+ if (response.status === 401) {
724
+ const local = readStoredSessions().filter((s) => s.sessionId !== sid);
725
+ writeStoredSessions(local);
726
+ setSessions(local.map((x) => x.sessionId));
727
+ setActiveSessionId(null);
728
+ setActiveSessionIdState(null);
729
+ const newSid = await createNewSession();
730
+ const retry = await fetch(`${PROXY_BASE_URL}/aizek-chat?clientId=${clientId}`, {
731
+ method: "POST",
732
+ headers: {
733
+ "Content-Type": "application/json",
734
+ "x-device-id": deviceId,
735
+ "x-session-id": newSid,
736
+ "x-alternate": JSON.stringify(headers)
737
+ },
738
+ body: JSON.stringify({ message })
739
+ });
740
+ if (!retry.ok) throw new Error(`HTTP error ${retry.status}`);
741
+ const retryJson = await retry.json();
742
+ const text = JSON.stringify(retryJson.data);
743
+ const { cleanedText, uiData } = extractUIJsonFromText(text);
744
+ addMessage({ text: cleanedText, ui: uiData, role: "assistant" });
745
+ touchSession(newSid);
746
+ return;
747
+ }
748
+ if (!response.ok) {
749
+ throw new Error(`HTTP error ${response.status}`);
750
+ }
751
+ if (!response.body) {
752
+ throw new Error("Streaming desteklenmiyor (response.body yok)");
753
+ }
754
+ const reader = response.body.getReader();
755
+ const decoder = new TextDecoder();
756
+ let buffer = "";
757
+ while (true) {
758
+ const { value, done } = await reader.read();
759
+ if (done) break;
760
+ buffer += decoder.decode(value, { stream: true });
761
+ const chunks = buffer.split("\n\n");
762
+ buffer = chunks.pop() ?? "";
763
+ for (const rawChunk of chunks) {
764
+ const line = rawChunk.split("\n").find((l) => l.startsWith("data:"));
765
+ if (!line) continue;
766
+ const jsonStr = line.replace(/^data:\s*/, "").trim();
767
+ if (!jsonStr) continue;
768
+ const event = JSON.parse(jsonStr);
769
+ if (event.type === "assistant_text" && event.content) {
770
+ const { cleanedText, uiData } = extractUIJsonFromText(event.content);
771
+ addMessage({
772
+ text: cleanedText,
773
+ ui: uiData,
774
+ role: "assistant"
775
+ });
776
+ }
777
+ if (event.type === "assistant_tool_result" && event.content) {
778
+ const toolInfoParsed = JSON.parse(event.content);
779
+ onToolCall?.(toolInfoParsed);
780
+ }
781
+ if (event.type === "error" && event.content) {
782
+ const { cleanedText, uiData } = extractUIJsonFromText(event.content);
783
+ addMessage({
784
+ text: cleanedText,
785
+ ui: uiData,
786
+ role: "assistant"
787
+ });
788
+ }
789
+ }
790
+ }
791
+ touchSession(sid);
792
+ } catch (error) {
793
+ console.error("Error sending message:", error);
794
+ addMessage({ text: "Sorry, something went wrong. Please try again.", role: "assistant" });
795
+ } finally {
796
+ setIsLoading(false);
797
+ }
798
+ };
799
+ const disconnectActiveSession = async () => {
800
+ try {
801
+ const deviceId = getOrCreateDeviceId();
802
+ const sid = activeSessionId;
803
+ if (!sid) return;
804
+ await fetch(`${PROXY_BASE_URL}/aizek-disconnect?clientId=${clientId}`, {
805
+ method: "POST",
806
+ headers: {
807
+ "Content-Type": "application/json",
808
+ "x-device-id": deviceId,
809
+ "x-session-id": sid,
810
+ "x-alternate": JSON.stringify(headers)
811
+ },
812
+ body: JSON.stringify({ sessionId: sid })
813
+ });
814
+ const nextStored = readStoredSessions().filter((s) => s.sessionId !== sid);
815
+ writeStoredSessions(nextStored);
816
+ const nextSessions = nextStored.map((x) => x.sessionId);
817
+ setSessions(nextSessions);
818
+ const nextActive = nextSessions[0] ?? null;
819
+ setActiveSessionIdState(nextActive);
820
+ setActiveSessionId(nextActive);
821
+ setMessages([]);
822
+ onDisconnect?.();
823
+ } catch (e) {
824
+ console.error(e);
825
+ }
826
+ };
827
+ const handleSelectSession = (sid) => {
828
+ setActiveSessionIdState(sid);
829
+ setActiveSessionId(sid);
830
+ setActiveTab("messages");
831
+ setMessageView("detail");
832
+ };
833
+ const getSessionTitle = (sid) => {
834
+ if (sessionTitleById[sid]) return sessionTitleById[sid];
835
+ return "New conversation";
836
+ };
837
+ const fetchLastMessageTitle = async (sid) => {
838
+ try {
839
+ const deviceId = getOrCreateDeviceId();
840
+ const res = await fetch(`${PROXY_BASE_URL}/aizek-last-message`, {
841
+ method: "GET",
842
+ headers: {
843
+ "Content-Type": "application/json",
844
+ "x-device-id": deviceId,
845
+ "x-session-id": sid,
846
+ "x-alternate": JSON.stringify(headers)
847
+ }
848
+ });
849
+ const json = await res.json();
850
+ if (!json?.success) return null;
851
+ const last = json?.data?.lastMessage;
852
+ if (!last) return null;
853
+ let textContent = "";
854
+ if (typeof last.content === "string") {
855
+ textContent = last.content;
856
+ } else if (Array.isArray(last.content)) {
857
+ const parts = [];
858
+ for (const item of last.content) {
859
+ if (item?.type === "text" && typeof item.text === "string") parts.push(item.text);
860
+ }
861
+ textContent = parts.join("\n");
862
+ }
863
+ if (!textContent.trim()) return null;
864
+ const extracted = extractUIJsonFromText(textContent);
865
+ const cleaned = (extracted.cleanedText || "").trim();
866
+ const firstLine = (cleaned.split("\n").find((l) => l.trim()) || "").trim();
867
+ const title = firstLine || cleaned;
868
+ if (!title) return null;
869
+ const compact = title.length > 46 ? `${title.slice(0, 46).trim()}\u2026` : title;
870
+ return compact;
871
+ } catch (e) {
872
+ console.error("Failed to fetch last message title:", e);
873
+ return null;
874
+ }
875
+ };
876
+ const toggleChat = () => {
877
+ const newIsOpen = !isOpen;
878
+ setIsOpen(newIsOpen);
879
+ if (newIsOpen) onOpen?.();
880
+ else onClose?.();
881
+ };
882
+ const clean = sanitizeHtml__default.default(config?.widget_config.welcome_message ?? "", {
883
+ allowedTags: ["b", "i", "em", "strong", "a", "p", "br"],
884
+ allowedAttributes: {
885
+ a: ["href", "target", "rel"]
886
+ }
887
+ });
888
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: isConfigLoading ? /* @__PURE__ */ jsxRuntime.jsx(
889
+ "button",
890
+ {
891
+ className: "floating-button bottom-right button-sizes medium loading-state",
892
+ style: { background: "#4f46e5" },
893
+ "aria-label": "Loading",
894
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "loading-spinner" })
895
+ }
896
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
897
+ isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `overlay floating-chat-overlay ${isOpen ? "is-open" : ""}`, onClick: toggleChat }),
898
+ /* @__PURE__ */ jsxRuntime.jsx(
899
+ "div",
900
+ {
901
+ className: `chat-container ${config?.widget_config.button_position} ${isOpen ? "is-open" : ""}`,
902
+ style: { width: config?.widget_config.chat_width, height: config?.widget_config.chat_height },
903
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatbot-container", children: [
904
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "header", style: { background: config?.widget_config.header_background }, children: [
905
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "logo-container", children: config?.widget_config.company_logo ? config?.widget_config.company_logo.startsWith("http") || config?.widget_config.company_logo.startsWith("data:") ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: config?.widget_config.company_logo, alt: "Company Logo", className: "logo-image" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "logo-text", children: config?.widget_config.company_logo }) : "\u{1F916}" }),
906
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
907
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "company-name", children: config?.widget_config.company_name }),
908
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "status-text", children: isLoading ? "Typing..." : "Online" })
909
+ ] })
910
+ ] }),
911
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chat-content", children: [
912
+ activeTab === "home" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-panel", children: [
913
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Welcome" }),
914
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "panel-title", children: config?.widget_config.company_name }),
915
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "panel-subtitle", children: "Ask anything. We keep your history and respond instantly." }),
916
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "home-actions", children: [
917
+ /* @__PURE__ */ jsxRuntime.jsx(
918
+ "button",
919
+ {
920
+ className: "primary-button",
921
+ onClick: async () => {
922
+ try {
923
+ await createNewSession();
924
+ } catch (e) {
925
+ console.error(e);
926
+ }
927
+ },
928
+ disabled: isLoading || sessions.length >= MAX_SESSIONS,
929
+ children: "Start a new conversation"
930
+ }
931
+ ),
932
+ /* @__PURE__ */ jsxRuntime.jsx(
933
+ "button",
934
+ {
935
+ className: "ghost-button",
936
+ onClick: () => {
937
+ setActiveTab("messages");
938
+ setMessageView("list");
939
+ },
940
+ children: "View conversations"
941
+ }
942
+ )
943
+ ] })
944
+ ] }),
945
+ activeTab === "messages" && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: messageView === "list" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-list", children: [
946
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "list-header", children: [
947
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
948
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Conversations" }),
949
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "panel-title", children: "Inbox" })
950
+ ] }),
951
+ /* @__PURE__ */ jsxRuntime.jsx(
952
+ "button",
953
+ {
954
+ className: "session-new-button",
955
+ onClick: async () => {
956
+ try {
957
+ await createNewSession();
958
+ } catch (e) {
959
+ console.error(e);
960
+ }
961
+ },
962
+ disabled: sessions.length >= MAX_SESSIONS,
963
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "+ New" })
964
+ }
965
+ )
966
+ ] }),
967
+ sessions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "empty-list", children: [
968
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state-icon", children: "\u{1F4AC}" }),
969
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "empty-state-title", children: "No conversations yet" }),
970
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "empty-state-description", children: "Start a new conversation to see it appear here." })
971
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "conversation-items", children: sessions.map((sid) => /* @__PURE__ */ jsxRuntime.jsxs(
972
+ "button",
973
+ {
974
+ className: `conversation-item ${sid === activeSessionId ? "active" : ""}`,
975
+ onClick: () => handleSelectSession(sid),
976
+ children: [
977
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-meta", children: [
978
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "conversation-title", children: getSessionTitle(sid) }),
979
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "conversation-sub", children: [
980
+ "Session ID: ",
981
+ sid.slice(0, 8),
982
+ "..."
983
+ ] })
984
+ ] }),
985
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "conversation-pill", children: "Open" })
986
+ ]
987
+ },
988
+ sid
989
+ )) })
990
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "conversation-detail", children: [
991
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header", children: [
992
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-header-left", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "icon-button", onClick: () => setMessageView("list"), "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
993
+ "path",
994
+ {
995
+ d: "M15 18l-6-6 6-6",
996
+ stroke: "currentColor",
997
+ strokeWidth: "2",
998
+ strokeLinecap: "round",
999
+ strokeLinejoin: "round"
1000
+ }
1001
+ ) }) }) }),
1002
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-center", children: [
1003
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "detail-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx(
1004
+ "path",
1005
+ {
1006
+ 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",
1007
+ stroke: "currentColor",
1008
+ strokeWidth: "2",
1009
+ strokeLinejoin: "round"
1010
+ }
1011
+ ) }) }),
1012
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title", children: [
1013
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-title-row", children: [
1014
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "detail-title-text", children: activeSessionId ? getSessionTitle(activeSessionId) : "Chat" }),
1015
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `status-dot ${isLoading ? "typing" : "online"}`, "aria-hidden": "true" })
1016
+ ] }),
1017
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "detail-subtitle", children: isLoading ? "Yaz\u0131yor\u2026" : "Online" })
1018
+ ] })
1019
+ ] }),
1020
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "detail-header-right", children: [
1021
+ /* @__PURE__ */ jsxRuntime.jsx(
1022
+ "button",
1023
+ {
1024
+ className: "icon-button",
1025
+ onClick: () => {
1026
+ setActiveTab("info");
1027
+ setMessageView("list");
1028
+ },
1029
+ "aria-label": "Bilgi",
1030
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
1031
+ /* @__PURE__ */ jsxRuntime.jsx(
1032
+ "path",
1033
+ {
1034
+ d: "M12 17v-6",
1035
+ stroke: "currentColor",
1036
+ strokeWidth: "2",
1037
+ strokeLinecap: "round"
1038
+ }
1039
+ ),
1040
+ /* @__PURE__ */ jsxRuntime.jsx(
1041
+ "path",
1042
+ {
1043
+ d: "M12 8h.01",
1044
+ stroke: "currentColor",
1045
+ strokeWidth: "2.5",
1046
+ strokeLinecap: "round"
1047
+ }
1048
+ ),
1049
+ /* @__PURE__ */ jsxRuntime.jsx(
1050
+ "circle",
1051
+ {
1052
+ cx: "12",
1053
+ cy: "12",
1054
+ r: "9",
1055
+ stroke: "currentColor",
1056
+ strokeWidth: "2"
1057
+ }
1058
+ )
1059
+ ] })
1060
+ }
1061
+ ),
1062
+ /* @__PURE__ */ jsxRuntime.jsx(
1063
+ "button",
1064
+ {
1065
+ className: "icon-button danger",
1066
+ onClick: disconnectActiveSession,
1067
+ disabled: !activeSessionId,
1068
+ "aria-label": "End conversation",
1069
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: [
1070
+ /* @__PURE__ */ jsxRuntime.jsx(
1071
+ "path",
1072
+ {
1073
+ d: "M3 6h18",
1074
+ stroke: "currentColor",
1075
+ strokeWidth: "2",
1076
+ strokeLinecap: "round"
1077
+ }
1078
+ ),
1079
+ /* @__PURE__ */ jsxRuntime.jsx(
1080
+ "path",
1081
+ {
1082
+ d: "M8 6V4h8v2",
1083
+ stroke: "currentColor",
1084
+ strokeWidth: "2",
1085
+ strokeLinejoin: "round"
1086
+ }
1087
+ ),
1088
+ /* @__PURE__ */ jsxRuntime.jsx(
1089
+ "path",
1090
+ {
1091
+ d: "M6 6l1 16h10l1-16",
1092
+ stroke: "currentColor",
1093
+ strokeWidth: "2",
1094
+ strokeLinejoin: "round"
1095
+ }
1096
+ )
1097
+ ] })
1098
+ }
1099
+ )
1100
+ ] })
1101
+ ] }),
1102
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "messages-container", children: [
1103
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderAlert, { headerValidation, setShowAlert, showAlert }),
1104
+ messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "empty-state", children: /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: clean } }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1105
+ messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { message, onAction: sendMessage }, index)),
1106
+ config?.widget_config.show_typing_indicator && isLoading && /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {})
1107
+ ] }),
1108
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
1109
+ ] }),
1110
+ /* @__PURE__ */ jsxRuntime.jsx(
1111
+ ChatInput,
1112
+ {
1113
+ handleSendMessage: sendMessage,
1114
+ isLoading,
1115
+ placeholder: config?.widget_config.placeholder ?? ""
1116
+ }
1117
+ )
1118
+ ] }) }),
1119
+ activeTab === "info" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "info-panel", children: [
1120
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "eyebrow", children: "Info" }),
1121
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "panel-title", children: "Widget Details" }),
1122
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "info-list", children: [
1123
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1124
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Company" }),
1125
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: config?.widget_config.company_name })
1126
+ ] }),
1127
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1128
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Status" }),
1129
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: isLoading ? "Typing..." : "Online" })
1130
+ ] }),
1131
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1132
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Conversations" }),
1133
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: sessions.length })
1134
+ ] })
1135
+ ] })
1136
+ ] })
1137
+ ] }),
1138
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bottom-nav", children: [
1139
+ /* @__PURE__ */ jsxRuntime.jsx(
1140
+ "button",
1141
+ {
1142
+ className: `nav-button ${activeTab === "home" ? "active" : ""}`,
1143
+ onClick: () => {
1144
+ setActiveTab("home");
1145
+ setMessageView("list");
1146
+ },
1147
+ children: "Home"
1148
+ }
1149
+ ),
1150
+ /* @__PURE__ */ jsxRuntime.jsx(
1151
+ "button",
1152
+ {
1153
+ className: `nav-button ${activeTab === "messages" ? "active" : ""}`,
1154
+ onClick: () => {
1155
+ setActiveTab("messages");
1156
+ setMessageView("list");
1157
+ },
1158
+ children: "Messages"
1159
+ }
1160
+ ),
1161
+ /* @__PURE__ */ jsxRuntime.jsx(
1162
+ "button",
1163
+ {
1164
+ className: `nav-button ${activeTab === "info" ? "active" : ""}`,
1165
+ onClick: () => {
1166
+ setActiveTab("info");
1167
+ setMessageView("list");
1168
+ },
1169
+ children: "Info"
1170
+ }
1171
+ )
1172
+ ] })
1173
+ ] })
1174
+ }
1175
+ ),
1176
+ /* @__PURE__ */ jsxRuntime.jsx(
1177
+ "button",
1178
+ {
1179
+ onClick: toggleChat,
1180
+ className: `floating-button ${config?.widget_config.button_position} button-sizes ${config?.widget_config.button_size} ${isOpen ? "is-open" : ""}`,
1181
+ style: { background: config?.widget_config.button_background },
1182
+ children: isOpen ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h4l4 4 4-4h4c1.1 0-2 .9-2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z" }) })
1183
+ }
1184
+ )
1185
+ ] }) });
1186
+ };
1187
+
1188
+ exports.AizekChatBot = AizekChatBot;
1189
+ //# sourceMappingURL=index.cjs.map
1190
+ //# sourceMappingURL=index.cjs.map