@contenify/chatbot 0.1.0

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 ADDED
@@ -0,0 +1,2191 @@
1
+ "use client";
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+
22
+ // contexts/PreferencesContext.tsx
23
+ import { createContext, useContext, useState, useEffect } from "react";
24
+
25
+ // lib/api.ts
26
+ import axios from "axios";
27
+
28
+ // lib/config.ts
29
+ var DEFAULT_API_BASE_URL = "http://localhost:8080/api";
30
+ function getApiBaseUrl() {
31
+ return process.env.NEXT_PUBLIC_CONTENIFY_API_URL || DEFAULT_API_BASE_URL;
32
+ }
33
+ function getServerBaseUrl() {
34
+ const apiUrl = getApiBaseUrl();
35
+ return apiUrl.replace(/\/api\/?$/, "");
36
+ }
37
+
38
+ // lib/api.ts
39
+ var api = axios.create({
40
+ baseURL: getApiBaseUrl(),
41
+ withCredentials: true,
42
+ headers: {
43
+ "Content-Type": "application/json"
44
+ }
45
+ });
46
+ api.interceptors.request.use(
47
+ (config) => {
48
+ const apiKey = process.env.NEXT_PUBLIC_API_KEY;
49
+ if (apiKey) {
50
+ config.headers["x-api-key"] = apiKey;
51
+ }
52
+ return config;
53
+ },
54
+ (error) => Promise.reject(error)
55
+ );
56
+ api.interceptors.response.use(
57
+ (response) => response,
58
+ (error) => {
59
+ var _a, _b;
60
+ const message = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message) || error.message || "Something went wrong";
61
+ return Promise.reject(message);
62
+ }
63
+ );
64
+ var api_default = api;
65
+
66
+ // services/preferences.service.ts
67
+ var getMyPreferencesApi = async () => {
68
+ const { data } = await api_default.get("/preferences/me");
69
+ return data.data;
70
+ };
71
+
72
+ // contexts/PreferencesContext.tsx
73
+ import { jsx } from "react/jsx-runtime";
74
+ var defaultPreferences = {
75
+ chatbot: {
76
+ name: "AI News Assistant",
77
+ primaryColor: "#10b981",
78
+ secondaryColor: "#064e3b",
79
+ theme: "system"
80
+ },
81
+ localization: {
82
+ country: "India",
83
+ state: "Uttar Pradesh",
84
+ cities: [],
85
+ language: "en",
86
+ locale: "en-IN",
87
+ timezone: "Asia/Kolkata"
88
+ },
89
+ appearance: {
90
+ showSidebar: true,
91
+ showHeader: true,
92
+ activeThemePreset: null,
93
+ showNewsPanel: true
94
+ },
95
+ content: {
96
+ tone: "engaging",
97
+ style: "blog",
98
+ wordCount: "medium",
99
+ includeQuotes: true,
100
+ includeFAQ: false,
101
+ targetAudience: ""
102
+ }
103
+ };
104
+ var PreferencesContext = createContext(void 0);
105
+ function PreferencesProvider({ children }) {
106
+ const [preferences, setPreferences] = useState(defaultPreferences);
107
+ const [loading, setLoading] = useState(true);
108
+ const [error, setError] = useState(null);
109
+ const refreshPreferences = async () => {
110
+ var _a, _b, _c;
111
+ try {
112
+ setLoading(true);
113
+ setError(null);
114
+ const data = await getMyPreferencesApi();
115
+ if (data) {
116
+ if (((_a = data.chatbot) == null ? void 0 : _a.logoUrl) && !data.chatbot.logoUrl.startsWith("http")) {
117
+ data.chatbot.logoUrl = `${getServerBaseUrl()}/${data.chatbot.logoUrl}`;
118
+ }
119
+ const mergedPreferences = __spreadProps(__spreadValues(__spreadValues({}, defaultPreferences), data), {
120
+ chatbot: __spreadValues(__spreadValues({}, defaultPreferences.chatbot), data.chatbot),
121
+ localization: __spreadValues(__spreadValues({}, defaultPreferences.localization), data.localization),
122
+ appearance: __spreadValues(__spreadValues({}, defaultPreferences.appearance), data.appearance),
123
+ content: __spreadValues(__spreadValues({}, defaultPreferences.content), data.content)
124
+ });
125
+ setPreferences(mergedPreferences);
126
+ if (typeof document !== "undefined") {
127
+ document.documentElement.style.setProperty("--color-primary", ((_b = mergedPreferences.chatbot) == null ? void 0 : _b.primaryColor) || "#10b981");
128
+ document.documentElement.style.setProperty("--color-secondary", ((_c = mergedPreferences.chatbot) == null ? void 0 : _c.secondaryColor) || "#064e3b");
129
+ }
130
+ }
131
+ } catch (err) {
132
+ console.error("Failed to fetch preferences:", err);
133
+ setError(err instanceof Error ? err.message : "Failed to load preferences");
134
+ setPreferences(defaultPreferences);
135
+ } finally {
136
+ setLoading(false);
137
+ }
138
+ };
139
+ const updatePreferences = (newPreferences) => {
140
+ var _a, _b;
141
+ setPreferences(newPreferences);
142
+ if (typeof document !== "undefined") {
143
+ document.documentElement.style.setProperty("--color-primary", ((_a = newPreferences.chatbot) == null ? void 0 : _a.primaryColor) || "#10b981");
144
+ document.documentElement.style.setProperty("--color-secondary", ((_b = newPreferences.chatbot) == null ? void 0 : _b.secondaryColor) || "#064e3b");
145
+ }
146
+ };
147
+ useEffect(() => {
148
+ refreshPreferences();
149
+ }, []);
150
+ return /* @__PURE__ */ jsx(
151
+ PreferencesContext.Provider,
152
+ {
153
+ value: {
154
+ preferences,
155
+ loading,
156
+ error,
157
+ refreshPreferences,
158
+ updatePreferences
159
+ },
160
+ children
161
+ }
162
+ );
163
+ }
164
+ function usePreferences() {
165
+ const context = useContext(PreferencesContext);
166
+ if (context === void 0) {
167
+ throw new Error("usePreferences must be used within a PreferencesProvider");
168
+ }
169
+ return context;
170
+ }
171
+
172
+ // components/chatbot/ChatBot.tsx
173
+ import { useState as useState8, useCallback as useCallback3 } from "react";
174
+
175
+ // components/chatbot/ArticleModal.tsx
176
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
177
+ function ArticleModal({
178
+ article,
179
+ onClose,
180
+ onRecreate
181
+ }) {
182
+ return /* @__PURE__ */ jsx2("div", { className: "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm flex items-center justify-center px-4", children: /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-3xl bg-white rounded-xl shadow-card border border-gray-200 animate-in fade-in zoom-in", children: [
183
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between px-6 py-4 border-b border-gray-300", children: [
184
+ /* @__PURE__ */ jsxs("div", { children: [
185
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-gray-500 mb-1", children: "Source Article" }),
186
+ /* @__PURE__ */ jsx2("h2", { className: "text-lg font-semibold text-gray-900 leading-snug", children: article.title })
187
+ ] }),
188
+ /* @__PURE__ */ jsx2(
189
+ "button",
190
+ {
191
+ onClick: onClose,
192
+ className: "text-gray-400 hover:text-gray-700 transition",
193
+ "aria-label": "Close modal",
194
+ children: "\u2715"
195
+ }
196
+ )
197
+ ] }),
198
+ /* @__PURE__ */ jsx2("div", { className: "px-6 py-5 max-h-[65vh] overflow-y-auto", children: /* @__PURE__ */ jsx2("div", { className: "prose prose-sm max-w-none text-gray-800", children: article.content }) }),
199
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-t bg-gray-50 rounded-b-xl", children: [
200
+ /* @__PURE__ */ jsx2("span", { className: "text-xs text-gray-400", children: "This content will be recreated using AI" }),
201
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
202
+ /* @__PURE__ */ jsx2(
203
+ "button",
204
+ {
205
+ onClick: onClose,
206
+ className: "px-4 py-2 text-sm rounded-md border border-gray-300 text-gray-700 hover:bg-gray-100 transition",
207
+ children: "Cancel"
208
+ }
209
+ ),
210
+ /* @__PURE__ */ jsx2(
211
+ "button",
212
+ {
213
+ onClick: () => onRecreate({
214
+ title: article.title,
215
+ content: article.content,
216
+ id: article._id
217
+ // Include article ID when available
218
+ }),
219
+ className: "px-4 py-2 text-sm rounded-md bg-gray-900 text-white hover:bg-black transition",
220
+ children: "Recreate Article"
221
+ }
222
+ )
223
+ ] })
224
+ ] })
225
+ ] }) });
226
+ }
227
+
228
+ // util/util.ts
229
+ function extractArticleContent(raw) {
230
+ if (!raw) {
231
+ return { article: "", metaKeywords: [] };
232
+ }
233
+ if (!raw.trim().startsWith("{")) {
234
+ return {
235
+ article: raw,
236
+ metaKeywords: []
237
+ };
238
+ }
239
+ try {
240
+ const parsed = JSON.parse(raw);
241
+ return {
242
+ title: parsed.title || "",
243
+ article: parsed.article || parsed.content || "",
244
+ metaKeywords: Array.isArray(parsed.metaKeywords) ? parsed.metaKeywords : []
245
+ };
246
+ } catch (e) {
247
+ const article = raw.replace(/^[\s\S]*?"article"\s*:\s*"/, "").replace(/"\s*,\s*"metaKeywords"[\s\S]*$/, "").replace(/"}\s*$/, "") || raw;
248
+ return {
249
+ article,
250
+ metaKeywords: []
251
+ };
252
+ }
253
+ }
254
+
255
+ // components/chatbot/ChatWindow.tsx
256
+ import { Check, Copy, Edit3, Send, SendHorizontal, Zap, X as X2, RefreshCcw as RefreshCcw2, FileText, ListChecks, Share2, BookOpen, Mail, Key } from "lucide-react";
257
+ import { useLayoutEffect, useRef, useState as useState4, useEffect as useEffect4 } from "react";
258
+
259
+ // components/chatbot/EditModal.tsx
260
+ import { X } from "lucide-react";
261
+ import { useEffect as useEffect3, useState as useState2 } from "react";
262
+
263
+ // components/chatbot/RichTextEditor.tsx
264
+ import { useEditor, EditorContent } from "@tiptap/react";
265
+ import StarterKit from "@tiptap/starter-kit";
266
+ import Placeholder from "@tiptap/extension-placeholder";
267
+ import {
268
+ Bold,
269
+ Italic,
270
+ List,
271
+ ListOrdered,
272
+ Heading1,
273
+ Heading2,
274
+ Undo,
275
+ Redo,
276
+ Pilcrow
277
+ } from "lucide-react";
278
+ import { useEffect as useEffect2 } from "react";
279
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
280
+ function RichTextEditor({
281
+ content,
282
+ onChange,
283
+ placeholder = "Start writing your article..."
284
+ }) {
285
+ const editor = useEditor({
286
+ immediatelyRender: false,
287
+ // Prevents SSR hydration mismatch
288
+ extensions: [
289
+ StarterKit.configure({
290
+ heading: {
291
+ levels: [1, 2]
292
+ }
293
+ }),
294
+ Placeholder.configure({
295
+ placeholder
296
+ })
297
+ ],
298
+ content,
299
+ editorProps: {
300
+ attributes: {
301
+ class: "prose prose-sm max-w-none focus:outline-none min-h-[350px] p-4"
302
+ }
303
+ },
304
+ onUpdate: ({ editor: editor2 }) => {
305
+ onChange(editor2.getHTML());
306
+ }
307
+ });
308
+ useEffect2(() => {
309
+ if (editor && content !== editor.getHTML()) {
310
+ editor.commands.setContent(content);
311
+ }
312
+ }, [content, editor]);
313
+ if (!editor) {
314
+ return /* @__PURE__ */ jsx3("div", { className: "w-full h-[400px] border border-gray-300 rounded-lg flex items-center justify-center text-gray-400", children: "Loading editor..." });
315
+ }
316
+ return /* @__PURE__ */ jsxs2("div", { className: "w-full border border-gray-300 rounded-lg overflow-hidden", children: [
317
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap items-center gap-1 p-2 border-b border-gray-200 bg-gray-50", children: [
318
+ /* @__PURE__ */ jsx3(
319
+ ToolbarButton,
320
+ {
321
+ onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(),
322
+ isActive: editor.isActive("heading", { level: 1 }),
323
+ title: "Heading 1",
324
+ children: /* @__PURE__ */ jsx3(Heading1, { size: 18 })
325
+ }
326
+ ),
327
+ /* @__PURE__ */ jsx3(
328
+ ToolbarButton,
329
+ {
330
+ onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(),
331
+ isActive: editor.isActive("heading", { level: 2 }),
332
+ title: "Heading 2",
333
+ children: /* @__PURE__ */ jsx3(Heading2, { size: 18 })
334
+ }
335
+ ),
336
+ /* @__PURE__ */ jsx3(
337
+ ToolbarButton,
338
+ {
339
+ onClick: () => editor.chain().focus().setParagraph().run(),
340
+ isActive: editor.isActive("paragraph"),
341
+ title: "Paragraph",
342
+ children: /* @__PURE__ */ jsx3(Pilcrow, { size: 18 })
343
+ }
344
+ ),
345
+ /* @__PURE__ */ jsx3("div", { className: "w-px h-6 bg-gray-300 mx-1" }),
346
+ /* @__PURE__ */ jsx3(
347
+ ToolbarButton,
348
+ {
349
+ onClick: () => editor.chain().focus().toggleBold().run(),
350
+ isActive: editor.isActive("bold"),
351
+ title: "Bold",
352
+ children: /* @__PURE__ */ jsx3(Bold, { size: 18 })
353
+ }
354
+ ),
355
+ /* @__PURE__ */ jsx3(
356
+ ToolbarButton,
357
+ {
358
+ onClick: () => editor.chain().focus().toggleItalic().run(),
359
+ isActive: editor.isActive("italic"),
360
+ title: "Italic",
361
+ children: /* @__PURE__ */ jsx3(Italic, { size: 18 })
362
+ }
363
+ ),
364
+ /* @__PURE__ */ jsx3("div", { className: "w-px h-6 bg-gray-300 mx-1" }),
365
+ /* @__PURE__ */ jsx3(
366
+ ToolbarButton,
367
+ {
368
+ onClick: () => editor.chain().focus().toggleBulletList().run(),
369
+ isActive: editor.isActive("bulletList"),
370
+ title: "Bullet List",
371
+ children: /* @__PURE__ */ jsx3(List, { size: 18 })
372
+ }
373
+ ),
374
+ /* @__PURE__ */ jsx3(
375
+ ToolbarButton,
376
+ {
377
+ onClick: () => editor.chain().focus().toggleOrderedList().run(),
378
+ isActive: editor.isActive("orderedList"),
379
+ title: "Numbered List",
380
+ children: /* @__PURE__ */ jsx3(ListOrdered, { size: 18 })
381
+ }
382
+ ),
383
+ /* @__PURE__ */ jsx3("div", { className: "w-px h-6 bg-gray-300 mx-1" }),
384
+ /* @__PURE__ */ jsx3(
385
+ ToolbarButton,
386
+ {
387
+ onClick: () => editor.chain().focus().undo().run(),
388
+ disabled: !editor.can().undo(),
389
+ title: "Undo",
390
+ children: /* @__PURE__ */ jsx3(Undo, { size: 18 })
391
+ }
392
+ ),
393
+ /* @__PURE__ */ jsx3(
394
+ ToolbarButton,
395
+ {
396
+ onClick: () => editor.chain().focus().redo().run(),
397
+ disabled: !editor.can().redo(),
398
+ title: "Redo",
399
+ children: /* @__PURE__ */ jsx3(Redo, { size: 18 })
400
+ }
401
+ )
402
+ ] }),
403
+ /* @__PURE__ */ jsx3(EditorContent, { editor, className: "min-h-[350px]" })
404
+ ] });
405
+ }
406
+ function ToolbarButton({
407
+ onClick,
408
+ isActive,
409
+ disabled,
410
+ title,
411
+ children
412
+ }) {
413
+ return /* @__PURE__ */ jsx3(
414
+ "button",
415
+ {
416
+ onClick,
417
+ disabled,
418
+ title,
419
+ className: `p-2 rounded hover:bg-gray-200 transition-colors ${isActive ? "bg-gray-200 text-emerald-600" : "text-gray-600"} ${disabled ? "opacity-40 cursor-not-allowed" : ""}`,
420
+ children
421
+ }
422
+ );
423
+ }
424
+
425
+ // hooks/useTheme.ts
426
+ function useTheme() {
427
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
428
+ const { preferences, loading } = usePreferences();
429
+ return {
430
+ loading,
431
+ primaryColor: ((_a = preferences == null ? void 0 : preferences.chatbot) == null ? void 0 : _a.primaryColor) || "#10b981",
432
+ secondaryColor: ((_b = preferences == null ? void 0 : preferences.chatbot) == null ? void 0 : _b.secondaryColor) || "#064e3b",
433
+ botName: ((_c = preferences == null ? void 0 : preferences.chatbot) == null ? void 0 : _c.name) || "AI News Assistant",
434
+ logoUrl: (_d = preferences == null ? void 0 : preferences.chatbot) == null ? void 0 : _d.logoUrl,
435
+ theme: ((_e = preferences == null ? void 0 : preferences.chatbot) == null ? void 0 : _e.theme) || "system",
436
+ showSidebar: (_g = (_f = preferences == null ? void 0 : preferences.appearance) == null ? void 0 : _f.showSidebar) != null ? _g : true,
437
+ showHeader: (_i = (_h = preferences == null ? void 0 : preferences.appearance) == null ? void 0 : _h.showHeader) != null ? _i : true,
438
+ activeThemePreset: (_k = (_j = preferences == null ? void 0 : preferences.appearance) == null ? void 0 : _j.activeThemePreset) != null ? _k : null,
439
+ showNewsPanel: (_m = (_l = preferences == null ? void 0 : preferences.appearance) == null ? void 0 : _l.showNewsPanel) != null ? _m : true
440
+ };
441
+ }
442
+
443
+ // components/chatbot/EditModal.tsx
444
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
445
+ function EditModal({
446
+ isOpen,
447
+ initialContent,
448
+ metaKeywords,
449
+ onClose,
450
+ onSaveDraft,
451
+ onPost
452
+ }) {
453
+ const { primaryColor } = useTheme();
454
+ const [content, setContent] = useState2("");
455
+ const [keywords, setKeywords] = useState2(metaKeywords);
456
+ const [newKeyword, setNewKeyword] = useState2("");
457
+ const markdownToHtml = (text) => {
458
+ const lines = text.split("\n").filter((line) => line.trim());
459
+ let html = "";
460
+ lines.forEach((line) => {
461
+ const trimmed = line.trim();
462
+ if (trimmed.startsWith("# ")) {
463
+ html += `<h1>${trimmed.replace(/^#\s+/, "")}</h1>`;
464
+ } else if (trimmed.startsWith("## ")) {
465
+ html += `<h2>${trimmed.replace(/^##\s+/, "")}</h2>`;
466
+ } else {
467
+ html += `<p>${trimmed}</p>`;
468
+ }
469
+ });
470
+ return html;
471
+ };
472
+ useEffect3(() => {
473
+ const htmlContent = markdownToHtml(initialContent);
474
+ setContent(htmlContent);
475
+ setKeywords(metaKeywords);
476
+ }, [initialContent, metaKeywords]);
477
+ useEffect3(() => {
478
+ if (isOpen) {
479
+ document.body.style.overflow = "hidden";
480
+ } else {
481
+ document.body.style.overflow = "";
482
+ }
483
+ return () => {
484
+ document.body.style.overflow = "";
485
+ };
486
+ }, [isOpen]);
487
+ const handleAddKeyword = () => {
488
+ if (newKeyword.trim() && !keywords.includes(newKeyword.trim())) {
489
+ setKeywords([...keywords, newKeyword.trim()]);
490
+ setNewKeyword("");
491
+ }
492
+ };
493
+ const handleRemoveKeyword = (index) => {
494
+ setKeywords(keywords.filter((_, i) => i !== index));
495
+ };
496
+ const handleKeyDown = (e) => {
497
+ if (e.key === "Enter") {
498
+ e.preventDefault();
499
+ handleAddKeyword();
500
+ }
501
+ };
502
+ if (!isOpen) return null;
503
+ return /* @__PURE__ */ jsxs3("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
504
+ /* @__PURE__ */ jsx4(
505
+ "div",
506
+ {
507
+ className: "absolute inset-0 bg-black/50",
508
+ onClick: onClose
509
+ }
510
+ ),
511
+ /* @__PURE__ */ jsxs3("div", { className: "relative w-full h-full max-w-5xl max-h-[90vh] m-4 bg-white rounded-xl shadow-2xl flex flex-col overflow-hidden", children: [
512
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between px-6 py-4 border-b", children: [
513
+ /* @__PURE__ */ jsx4("h2", { className: "text-xl font-semibold text-gray-900", children: "Edit Article" }),
514
+ /* @__PURE__ */ jsx4(
515
+ "button",
516
+ {
517
+ onClick: onClose,
518
+ className: "p-2 rounded-full hover:bg-gray-100 transition-colors",
519
+ children: /* @__PURE__ */ jsx4(X, { size: 20, className: "text-gray-500" })
520
+ }
521
+ )
522
+ ] }),
523
+ /* @__PURE__ */ jsxs3("div", { className: "flex-1 overflow-y-auto p-6 space-y-6", children: [
524
+ /* @__PURE__ */ jsxs3("div", { children: [
525
+ /* @__PURE__ */ jsx4("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Article Content" }),
526
+ /* @__PURE__ */ jsx4(
527
+ RichTextEditor,
528
+ {
529
+ content,
530
+ onChange: setContent,
531
+ placeholder: "Start writing your article..."
532
+ }
533
+ )
534
+ ] }),
535
+ /* @__PURE__ */ jsxs3("div", { children: [
536
+ /* @__PURE__ */ jsx4("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Meta Keywords" }),
537
+ /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-2 mb-3", children: keywords.map((keyword, index) => /* @__PURE__ */ jsxs3(
538
+ "span",
539
+ {
540
+ className: "inline-flex items-center gap-1 px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm",
541
+ children: [
542
+ "#",
543
+ keyword,
544
+ /* @__PURE__ */ jsx4(
545
+ "button",
546
+ {
547
+ onClick: () => handleRemoveKeyword(index),
548
+ className: "ml-1 text-gray-400 hover:text-gray-600",
549
+ children: /* @__PURE__ */ jsx4(X, { size: 14 })
550
+ }
551
+ )
552
+ ]
553
+ },
554
+ index
555
+ )) }),
556
+ /* @__PURE__ */ jsxs3("div", { className: "flex gap-2", children: [
557
+ /* @__PURE__ */ jsx4(
558
+ "input",
559
+ {
560
+ type: "text",
561
+ value: newKeyword,
562
+ onChange: (e) => setNewKeyword(e.target.value),
563
+ onKeyDown: handleKeyDown,
564
+ placeholder: "Add a keyword...",
565
+ className: "flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500"
566
+ }
567
+ ),
568
+ /* @__PURE__ */ jsx4(
569
+ "button",
570
+ {
571
+ onClick: handleAddKeyword,
572
+ className: "px-4 py-2 bg-gray-100 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-200 transition-colors",
573
+ children: "Add"
574
+ }
575
+ )
576
+ ] })
577
+ ] })
578
+ ] }),
579
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t bg-gray-50", children: [
580
+ /* @__PURE__ */ jsx4(
581
+ "button",
582
+ {
583
+ onClick: onClose,
584
+ className: "px-4 py-2 text-gray-700 text-sm font-medium hover:bg-gray-100 rounded-lg transition-colors",
585
+ children: "Cancel"
586
+ }
587
+ ),
588
+ /* @__PURE__ */ jsx4(
589
+ "button",
590
+ {
591
+ onClick: () => onSaveDraft(content, keywords),
592
+ className: "px-4 py-2 bg-gray-200 text-gray-800 text-sm font-medium rounded-lg hover:bg-gray-300 transition-colors",
593
+ children: "Save Draft"
594
+ }
595
+ ),
596
+ /* @__PURE__ */ jsx4(
597
+ "button",
598
+ {
599
+ onClick: () => onPost(content, keywords),
600
+ className: "px-4 py-2 bg-emerald-600 text-white text-sm font-medium rounded-lg hover:bg-emerald-700 transition-colors",
601
+ style: { backgroundColor: primaryColor, color: "#fff" },
602
+ children: "Post"
603
+ }
604
+ )
605
+ ] })
606
+ ] })
607
+ ] });
608
+ }
609
+
610
+ // components/news/NewsList.tsx
611
+ import { useState as useState3 } from "react";
612
+ import { Eye, RefreshCcw } from "lucide-react";
613
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
614
+ var dateFormatter = new Intl.DateTimeFormat("en-GB", {
615
+ day: "2-digit",
616
+ month: "short",
617
+ year: "numeric"
618
+ });
619
+ var timeFormatter = new Intl.DateTimeFormat("en-GB", {
620
+ hour: "2-digit",
621
+ minute: "2-digit",
622
+ hour12: false
623
+ });
624
+ function extractLinksFromContent(html) {
625
+ if (!html) return [];
626
+ const parser = new DOMParser();
627
+ const doc = parser.parseFromString(html, "text/html");
628
+ return Array.from(doc.querySelectorAll("li")).map((li) => {
629
+ const anchor = li.querySelector("a");
630
+ const source = li.querySelector("font");
631
+ return {
632
+ title: (anchor == null ? void 0 : anchor.textContent) || "",
633
+ url: (anchor == null ? void 0 : anchor.getAttribute("href")) || "#",
634
+ source: (source == null ? void 0 : source.textContent) || ""
635
+ };
636
+ });
637
+ }
638
+ function NewsList({
639
+ news,
640
+ onView,
641
+ onRecreate
642
+ }) {
643
+ const { primaryColor } = useTheme();
644
+ const [primaryColorState] = useState3(primaryColor);
645
+ const lightenColor = (hex, percent = 85) => {
646
+ hex = hex.replace("#", "");
647
+ let r = parseInt(hex.substring(0, 2), 16);
648
+ let g = parseInt(hex.substring(2, 4), 16);
649
+ let b = parseInt(hex.substring(4, 6), 16);
650
+ r = Math.round(r + (255 - r) * (percent / 100));
651
+ g = Math.round(g + (255 - g) * (percent / 100));
652
+ b = Math.round(b + (255 - b) * (percent / 100));
653
+ return `rgb(${r}, ${g}, ${b})`;
654
+ };
655
+ return /* @__PURE__ */ jsx5("div", { className: "p-4 space-y-3", children: news.flatMap((item) => {
656
+ const publishedDate = new Date(item.publishedAt);
657
+ const links = extractLinksFromContent(item.content);
658
+ if (links.length > 0) {
659
+ return links.map((link, idx) => /* @__PURE__ */ jsxs4(
660
+ "div",
661
+ {
662
+ className: "flex items-start justify-between gap-3 rounded-lg border border-gray-200 bg-white p-3 text-sm hover:bg-gray-50 transition",
663
+ children: [
664
+ /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
665
+ /* @__PURE__ */ jsx5("p", { className: "font-bold text-gray-900 line-clamp-2", children: link.title }),
666
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-2 mt-2 text-xs text-gray-500", children: [
667
+ /* @__PURE__ */ jsx5(
668
+ "span",
669
+ {
670
+ className: "inline-flex items-center rounded-full px-2 py-0.5 font-medium border",
671
+ style: {
672
+ backgroundColor: lightenColor(primaryColorState, 95),
673
+ color: primaryColor,
674
+ borderColor: lightenColor(primaryColorState, 95)
675
+ },
676
+ children: link.source || item.sourceName
677
+ }
678
+ ),
679
+ /* @__PURE__ */ jsx5("span", { children: "\u2022" }),
680
+ /* @__PURE__ */ jsx5("span", { className: "capitalize", children: item.category }),
681
+ /* @__PURE__ */ jsx5("span", { children: "\u2022" }),
682
+ /* @__PURE__ */ jsxs4("span", { children: [
683
+ dateFormatter.format(publishedDate),
684
+ " ",
685
+ timeFormatter.format(publishedDate)
686
+ ] })
687
+ ] })
688
+ ] }),
689
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2 shrink-0", children: [
690
+ /* @__PURE__ */ jsx5(
691
+ "button",
692
+ {
693
+ onClick: () => window.open(link.url, "_blank"),
694
+ className: "p-1 text-gray-400 hover:text-gray-700",
695
+ title: "View",
696
+ children: /* @__PURE__ */ jsx5(Eye, { size: 16 })
697
+ }
698
+ ),
699
+ /* @__PURE__ */ jsx5(
700
+ "button",
701
+ {
702
+ onClick: () => onRecreate({
703
+ title: link.title,
704
+ content: link.title,
705
+ id: item._id
706
+ // Include article ID
707
+ }),
708
+ className: "p-1 text-gray-400 hover:text-gray-700",
709
+ title: "Recreate",
710
+ children: /* @__PURE__ */ jsx5(RefreshCcw, { size: 16 })
711
+ }
712
+ )
713
+ ] })
714
+ ]
715
+ },
716
+ `${item._id}-link-${idx}`
717
+ ));
718
+ }
719
+ return /* @__PURE__ */ jsxs4(
720
+ "div",
721
+ {
722
+ className: "flex items-start justify-between gap-3 rounded-lg border border-gray-200 bg-white p-3 text-sm hover:bg-gray-50 transition",
723
+ children: [
724
+ /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
725
+ /* @__PURE__ */ jsx5("p", { className: "font-bold text-gray-900 line-clamp-2", children: item.title }),
726
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-2 mt-2 text-xs text-gray-500", children: [
727
+ /* @__PURE__ */ jsx5(
728
+ "span",
729
+ {
730
+ className: "inline-flex items-center rounded-full px-2 py-0.5 font-medium border",
731
+ style: {
732
+ backgroundColor: lightenColor(primaryColorState, 95),
733
+ color: primaryColor,
734
+ borderColor: lightenColor(primaryColorState, 95)
735
+ },
736
+ children: item.sourceName
737
+ }
738
+ ),
739
+ /* @__PURE__ */ jsx5("span", { children: "\u2022" }),
740
+ /* @__PURE__ */ jsx5("span", { className: "capitalize", children: item.category }),
741
+ /* @__PURE__ */ jsx5("span", { children: "\u2022" }),
742
+ /* @__PURE__ */ jsxs4("span", { children: [
743
+ dateFormatter.format(publishedDate),
744
+ " ",
745
+ timeFormatter.format(publishedDate)
746
+ ] })
747
+ ] })
748
+ ] }),
749
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2 shrink-0", children: [
750
+ /* @__PURE__ */ jsx5(
751
+ "button",
752
+ {
753
+ onClick: () => onView(item),
754
+ className: "p-1 text-gray-400 hover:text-gray-700",
755
+ title: "View",
756
+ children: /* @__PURE__ */ jsx5(Eye, { size: 16 })
757
+ }
758
+ ),
759
+ /* @__PURE__ */ jsx5(
760
+ "button",
761
+ {
762
+ onClick: () => onRecreate({
763
+ title: item.title,
764
+ content: item.content || item.title,
765
+ id: item._id
766
+ // Include article ID
767
+ }),
768
+ className: "p-1 text-gray-400 hover:text-gray-700",
769
+ title: "Recreate",
770
+ children: /* @__PURE__ */ jsx5(RefreshCcw, { size: 16 })
771
+ }
772
+ )
773
+ ] })
774
+ ]
775
+ },
776
+ item._id
777
+ );
778
+ }) });
779
+ }
780
+
781
+ // services/news.service.ts
782
+ var getTrendingNews = async () => {
783
+ const { data } = await api_default.get("/news/trending");
784
+ return data.data;
785
+ };
786
+ var getNewsSources = async () => {
787
+ const { data } = await api_default.get("/news/sources");
788
+ return data.data;
789
+ };
790
+ var scrapeNewsSource = async (sourceId) => {
791
+ const { data } = await api_default.post("/news/scrape-source", { sourceId });
792
+ return data.data;
793
+ };
794
+ var getNewsBySource = async (sourceId) => {
795
+ const { data } = await api_default.get(`/news/by-source/${sourceId}`);
796
+ return data.data;
797
+ };
798
+
799
+ // components/chatbot/ChatWindow.tsx
800
+ import Select from "react-select";
801
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
802
+ var ACTION_ICONS = {
803
+ recreate_article: RefreshCcw2,
804
+ create_summary: ListChecks,
805
+ create_social_posts: Share2,
806
+ create_blog_post: BookOpen,
807
+ create_newsletter: Mail,
808
+ extract_key_points: Key
809
+ };
810
+ function ChatWindow({
811
+ messages,
812
+ onSend,
813
+ onSelectNews,
814
+ isStreaming = false,
815
+ analyzedData,
816
+ onSelectAction
817
+ }) {
818
+ var _a, _b;
819
+ const { loading, showNewsPanel } = useTheme();
820
+ const bottomRef = useRef(null);
821
+ const textareaRef = useRef(null);
822
+ const dropdownRef = useRef(null);
823
+ const [input, setInput] = useState4("");
824
+ const [copiedId, setCopiedId] = useState4(null);
825
+ const [showNewsDropdown, setShowNewsDropdown] = useState4(false);
826
+ const [trendingNews, setTrendingNews] = useState4([]);
827
+ const [loadingNews, setLoadingNews] = useState4(false);
828
+ const [sources, setSources] = useState4([]);
829
+ const [selectedSource, setSelectedSource] = useState4(null);
830
+ const [loadingSources, setLoadingSources] = useState4(false);
831
+ const [scraping, setScraping] = useState4(false);
832
+ const [editModal, setEditModal] = useState4({ isOpen: false, content: "", metaKeywords: [], messageId: "" });
833
+ const { primaryColor } = useTheme();
834
+ const { preferences } = usePreferences();
835
+ const preferredLanguage = (_a = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _a.language;
836
+ const handleCopy = async (blocks, messageId) => {
837
+ try {
838
+ const formattedText = blocksToFormattedText(blocks);
839
+ await navigator.clipboard.writeText(formattedText);
840
+ setCopiedId(messageId);
841
+ setTimeout(() => setCopiedId(null), 2e3);
842
+ } catch (err) {
843
+ console.error("Failed to copy:", err);
844
+ }
845
+ };
846
+ const blocksToFormattedText = (blocks) => {
847
+ return blocks.map((block) => {
848
+ if (block.type === "h1") return `# ${block.text}`;
849
+ if (block.type === "h2") return `## ${block.text}`;
850
+ return block.text;
851
+ }).join("\n\n");
852
+ };
853
+ const handleEdit = (blocks, metaKeywords, messageId) => {
854
+ const formattedContent = blocksToFormattedText(blocks);
855
+ setEditModal({ isOpen: true, content: formattedContent, metaKeywords, messageId });
856
+ };
857
+ const handleCloseModal = () => {
858
+ setEditModal({ isOpen: false, content: "", metaKeywords: [], messageId: "" });
859
+ };
860
+ const handleSaveDraft = (content, keywords) => {
861
+ console.log("Saving draft:", { content, keywords });
862
+ handleCloseModal();
863
+ };
864
+ const handlePost = (content, keywords) => {
865
+ console.log("Posting:", { content, keywords });
866
+ handleCloseModal();
867
+ };
868
+ useLayoutEffect(() => {
869
+ var _a2;
870
+ (_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ block: "end" });
871
+ }, [messages]);
872
+ const handleSend = () => {
873
+ if (!input.trim()) return;
874
+ onSend(input);
875
+ setInput("");
876
+ if (textareaRef.current) {
877
+ textareaRef.current.style.height = "auto";
878
+ }
879
+ };
880
+ useEffect4(() => {
881
+ const textarea = textareaRef.current;
882
+ if (textarea) {
883
+ textarea.style.height = "auto";
884
+ textarea.style.height = `${textarea.scrollHeight}px`;
885
+ }
886
+ }, [input]);
887
+ const fetchSources = async () => {
888
+ setLoadingSources(true);
889
+ try {
890
+ const data = await getNewsSources();
891
+ setSources(data || []);
892
+ } catch (err) {
893
+ console.error("Failed to fetch sources:", err);
894
+ } finally {
895
+ setLoadingSources(false);
896
+ }
897
+ };
898
+ const fetchNews = async (sourceId) => {
899
+ setLoadingNews(true);
900
+ try {
901
+ let data;
902
+ if (sourceId) {
903
+ data = await getNewsBySource(sourceId);
904
+ } else {
905
+ data = await getTrendingNews();
906
+ }
907
+ setTrendingNews(data || []);
908
+ } catch (err) {
909
+ console.error("Failed to fetch news:", err);
910
+ } finally {
911
+ setLoadingNews(false);
912
+ }
913
+ };
914
+ const handleScrape = async () => {
915
+ if (!selectedSource) return;
916
+ setScraping(true);
917
+ try {
918
+ await scrapeNewsSource(selectedSource);
919
+ await fetchNews(selectedSource);
920
+ } catch (err) {
921
+ console.error("Failed to scrape:", err);
922
+ } finally {
923
+ setScraping(false);
924
+ }
925
+ };
926
+ const handleSourceSelect = (option) => {
927
+ var _a2;
928
+ const sourceId = (_a2 = option == null ? void 0 : option.value) != null ? _a2 : null;
929
+ console.log("Selected source:", option);
930
+ setSelectedSource(sourceId);
931
+ fetchNews(sourceId);
932
+ };
933
+ const handleOpenNewsDropdown = () => {
934
+ setShowNewsDropdown(true);
935
+ if (sources.length === 0) {
936
+ fetchSources();
937
+ }
938
+ if (trendingNews.length === 0) {
939
+ fetchNews(selectedSource);
940
+ }
941
+ };
942
+ useEffect4(() => {
943
+ const handleClickOutside = (event) => {
944
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
945
+ setShowNewsDropdown(false);
946
+ }
947
+ };
948
+ if (showNewsDropdown) {
949
+ document.addEventListener("mousedown", handleClickOutside);
950
+ }
951
+ return () => {
952
+ document.removeEventListener("mousedown", handleClickOutside);
953
+ };
954
+ }, [showNewsDropdown]);
955
+ function formatAIContent(raw) {
956
+ const extracted = extractArticleContent(raw);
957
+ if (!extracted || !extracted.article) {
958
+ return { blocks: [], metaKeywords: [] };
959
+ }
960
+ const { article, metaKeywords } = extracted;
961
+ const normalized = article.replace(/^H1:\s*/gm, "").replace(/^H2:\s*/gm, "").replace(/<\/h1>/gi, "\n").replace(/<\/h2>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<br\s*\/?>/gi, "\n");
962
+ const lines = normalized.split("\n").map((line) => line.replace(/<[^>]+>/g, "").trim()).filter(Boolean);
963
+ const blocks = [];
964
+ lines.forEach((line, index) => {
965
+ if (index === 0 && line.length < 120) {
966
+ blocks.push({ type: "h1", text: line });
967
+ return;
968
+ }
969
+ if (line.length < 90 && !line.endsWith("\u0964") && !line.endsWith(".")) {
970
+ blocks.push({ type: "h2", text: line });
971
+ return;
972
+ }
973
+ blocks.push({ type: "p", text: line });
974
+ });
975
+ return { blocks, metaKeywords };
976
+ }
977
+ return /* @__PURE__ */ jsxs5("div", { className: "h-full flex w-full flex-col", children: [
978
+ /* @__PURE__ */ jsx6("div", { className: "flex-1 px-4 py-6", children: /* @__PURE__ */ jsxs5("div", { className: "max-w-3xl chat-scroll mx-auto space-y-6", children: [
979
+ messages.map((msg) => {
980
+ var _a2;
981
+ const parsed = formatAIContent(msg.content);
982
+ return /* @__PURE__ */ jsxs5("div", { className: "flex gap-3", children: [
983
+ /* @__PURE__ */ jsx6("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx6(
984
+ "div",
985
+ {
986
+ className: "h-8 w-8 rounded-full flex items-center justify-center text-xs font-semibold text-white",
987
+ style: {
988
+ backgroundColor: msg.role === "assistant" ? primaryColor : "#1f2937"
989
+ },
990
+ children: msg.role === "assistant" ? "AI" : "You"
991
+ }
992
+ ) }),
993
+ /* @__PURE__ */ jsxs5("div", { className: "flex-1 text-sm space-y-3 leading-relaxed", children: [
994
+ msg.role === "assistant" && parsed.blocks.length > 0 && /* @__PURE__ */ jsx6("div", { className: "flex justify-end -mt-1 mb-2", children: /* @__PURE__ */ jsx6(
995
+ "button",
996
+ {
997
+ onClick: () => handleCopy(parsed.blocks, msg.id),
998
+ className: "p-1.5 rounded-md hover:bg-gray-100 transition-colors text-gray-400 hover:text-gray-600",
999
+ title: "Copy to clipboard",
1000
+ children: copiedId === msg.id ? /* @__PURE__ */ jsx6(Check, { size: 16, className: "text-emerald-600" }) : /* @__PURE__ */ jsx6(Copy, { size: 16 })
1001
+ }
1002
+ ) }),
1003
+ parsed.blocks.map((block, idx) => {
1004
+ if (block.type === "h1") {
1005
+ return /* @__PURE__ */ jsx6(
1006
+ "h1",
1007
+ {
1008
+ className: "text-sm font-semibold",
1009
+ children: block.text
1010
+ },
1011
+ idx
1012
+ );
1013
+ }
1014
+ if (block.type === "h2") {
1015
+ return /* @__PURE__ */ jsx6(
1016
+ "h2",
1017
+ {
1018
+ className: "text-base font-semibold mt-4",
1019
+ children: block.text
1020
+ },
1021
+ idx
1022
+ );
1023
+ }
1024
+ return /* @__PURE__ */ jsx6("p", { className: "text-gray-800", children: block.text }, idx);
1025
+ }),
1026
+ parsed.metaKeywords.length > 0 && /* @__PURE__ */ jsx6("div", { className: "pt-4 border-t mt-6", children: /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-2", children: parsed.metaKeywords.map((tag, i) => /* @__PURE__ */ jsxs5(
1027
+ "span",
1028
+ {
1029
+ className: "text-xs px-3 py-1 rounded-full bg-gray-100 text-gray-700",
1030
+ children: [
1031
+ "#",
1032
+ tag
1033
+ ]
1034
+ },
1035
+ i
1036
+ )) }) }),
1037
+ msg.role === "assistant" && (analyzedData == null ? void 0 : analyzedData.messageId) === msg.id && analyzedData.options.length > 0 && /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-2 pt-4 mt-2", children: analyzedData.options.map((option) => {
1038
+ const IconComponent = ACTION_ICONS[option.id] || FileText;
1039
+ return /* @__PURE__ */ jsxs5(
1040
+ "button",
1041
+ {
1042
+ onClick: () => onSelectAction == null ? void 0 : onSelectAction(option.id, analyzedData.url, analyzedData.content),
1043
+ className: "flex items-center gap-2 px-4 py-2 border border-gray-200 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 hover:border-gray-300 transition-colors",
1044
+ children: [
1045
+ /* @__PURE__ */ jsx6(IconComponent, { size: 16 }),
1046
+ option.name
1047
+ ]
1048
+ },
1049
+ option.id
1050
+ );
1051
+ }) }),
1052
+ msg.role === "assistant" && parsed.blocks.length > 0 && !(analyzedData == null ? void 0 : analyzedData.messageId) && (!isStreaming || msg.id !== ((_a2 = messages[messages.length - 1]) == null ? void 0 : _a2.id)) && /* @__PURE__ */ jsxs5("div", { className: "flex gap-3 pt-4 mt-2", children: [
1053
+ /* @__PURE__ */ jsxs5(
1054
+ "button",
1055
+ {
1056
+ onClick: () => handleEdit(parsed.blocks, parsed.metaKeywords, msg.id),
1057
+ className: "flex items-center gap-2 px-4 py-2 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors",
1058
+ children: [
1059
+ /* @__PURE__ */ jsx6(Edit3, { size: 16 }),
1060
+ "Edit"
1061
+ ]
1062
+ }
1063
+ ),
1064
+ /* @__PURE__ */ jsxs5(
1065
+ "button",
1066
+ {
1067
+ onClick: () => handlePost(msg.content, parsed.metaKeywords),
1068
+ className: "flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium text-white hover:bg-emerald-700 transition-colors",
1069
+ style: { backgroundColor: primaryColor, color: "#fff" },
1070
+ children: [
1071
+ /* @__PURE__ */ jsx6(Send, { size: 16 }),
1072
+ "Post"
1073
+ ]
1074
+ }
1075
+ )
1076
+ ] })
1077
+ ] })
1078
+ ] }, msg.id);
1079
+ }),
1080
+ /* @__PURE__ */ jsx6("div", { ref: bottomRef })
1081
+ ] }) }),
1082
+ /* @__PURE__ */ jsx6("div", { className: "shrink-0 bg-white px-4 py-3", children: /* @__PURE__ */ jsxs5("div", { className: "max-w-3xl mx-auto relative flex gap-2 items-end", children: [
1083
+ !showNewsPanel && /* @__PURE__ */ jsxs5("div", { ref: dropdownRef, className: "absolute left-3 top-1/2 -translate-y-1/2 z-10", children: [
1084
+ /* @__PURE__ */ jsx6(
1085
+ "button",
1086
+ {
1087
+ onClick: handleOpenNewsDropdown,
1088
+ className: "flex h-8 w-8 items-center justify-center rounded-full bg-gradient-to-r from-purple-500 to-pink-500 text-white hover:from-purple-600 hover:to-pink-600 transition-all animate-pulse hover:animate-none",
1089
+ title: "Select from trending news",
1090
+ children: /* @__PURE__ */ jsx6(Zap, { size: 16 })
1091
+ }
1092
+ ),
1093
+ showNewsDropdown && /* @__PURE__ */ jsxs5("div", { className: "absolute bottom-full left-0 mb-2 w-[600px] bg-white border border-gray-200 rounded-lg shadow-xl max-h-[600px] overflow-hidden", children: [
1094
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-3 py-2 border-b border-gray-100", style: { backgroundColor: primaryColor, color: "#fff" }, children: [
1095
+ /* @__PURE__ */ jsx6("span", { className: "text-sm font-medium text-white", children: "Select News" }),
1096
+ /* @__PURE__ */ jsx6(
1097
+ "button",
1098
+ {
1099
+ onClick: () => setShowNewsDropdown(false),
1100
+ className: "p-1 hover:bg-gray-200 rounded transition",
1101
+ style: { backgroundColor: primaryColor, color: "#fff" },
1102
+ children: /* @__PURE__ */ jsx6(X2, { size: 14, className: "text-white" })
1103
+ }
1104
+ )
1105
+ ] }),
1106
+ /* @__PURE__ */ jsxs5("div", { className: "px-3 py-2 border-b border-gray-100 flex items-center gap-2", children: [
1107
+ /* @__PURE__ */ jsx6("div", { className: "flex-1 min-w-[180px]", children: /* @__PURE__ */ jsx6(
1108
+ Select,
1109
+ {
1110
+ options: [
1111
+ { value: null, label: "All Sources (Trending)" },
1112
+ ...sources.filter((source) => !preferredLanguage || source.language === preferredLanguage).map((source) => ({
1113
+ value: source.id,
1114
+ label: source.name
1115
+ }))
1116
+ ],
1117
+ value: selectedSource ? { value: selectedSource, label: ((_b = sources.find((s) => s.id === selectedSource)) == null ? void 0 : _b.name) || selectedSource } : { value: null, label: "All Sources (Trending)" },
1118
+ onChange: handleSourceSelect,
1119
+ isLoading: loadingSources,
1120
+ isDisabled: loadingSources,
1121
+ placeholder: "Select source...",
1122
+ classNamePrefix: "react-select",
1123
+ menuPlacement: "bottom",
1124
+ menuPosition: "fixed",
1125
+ menuShouldScrollIntoView: false,
1126
+ maxMenuHeight: 220,
1127
+ menuPortalTarget: typeof window !== "undefined" ? document.body : null,
1128
+ styles: {
1129
+ container: (base) => __spreadProps(__spreadValues({}, base), {
1130
+ width: "100%"
1131
+ }),
1132
+ control: (base) => __spreadProps(__spreadValues({}, base), {
1133
+ minHeight: "38px",
1134
+ borderColor: "#e5e7eb",
1135
+ boxShadow: "none",
1136
+ width: "100%"
1137
+ }),
1138
+ menu: (base) => __spreadProps(__spreadValues({}, base), {
1139
+ width: "100%",
1140
+ zIndex: 999999
1141
+ }),
1142
+ menuPortal: (base) => __spreadProps(__spreadValues({}, base), {
1143
+ zIndex: 999999
1144
+ }),
1145
+ option: (base, state) => __spreadProps(__spreadValues({}, base), {
1146
+ backgroundColor: state.isSelected ? primaryColor : state.isFocused ? "#f3f4f6" : "white",
1147
+ color: state.isSelected ? "white" : "#374151",
1148
+ cursor: "pointer"
1149
+ })
1150
+ }
1151
+ }
1152
+ ) }),
1153
+ selectedSource && /* @__PURE__ */ jsxs5(
1154
+ "button",
1155
+ {
1156
+ onClick: handleScrape,
1157
+ disabled: scraping,
1158
+ className: "flex items-center gap-1.5 px-3 py-2 bg-emerald-600 text-white rounded-lg text-sm font-medium hover:bg-emerald-700 transition disabled:opacity-50",
1159
+ title: "Fetch latest news",
1160
+ children: [
1161
+ /* @__PURE__ */ jsx6(RefreshCcw2, { size: 14, className: scraping ? "animate-spin" : "" }),
1162
+ scraping ? "Scraping..." : "Scrape"
1163
+ ]
1164
+ }
1165
+ ),
1166
+ !selectedSource && /* @__PURE__ */ jsxs5(
1167
+ "button",
1168
+ {
1169
+ onClick: () => fetchNews(null),
1170
+ disabled: loadingNews,
1171
+ className: "flex items-center gap-1 px-3 py-2 text-sm text-gray-600 hover:text-gray-900 border border-gray-200 rounded-lg transition",
1172
+ children: [
1173
+ /* @__PURE__ */ jsx6(RefreshCcw2, { size: 14, className: loadingNews ? "animate-spin" : "" }),
1174
+ "Refresh"
1175
+ ]
1176
+ }
1177
+ )
1178
+ ] }),
1179
+ /* @__PURE__ */ jsx6("div", { className: "overflow-y-auto max-h-[320px]", children: loadingNews ? /* @__PURE__ */ jsx6("div", { className: "p-4 text-center text-sm text-gray-500", children: "Loading news..." }) : trendingNews.length === 0 ? /* @__PURE__ */ jsxs5("div", { className: "p-4 text-center text-sm text-gray-500", children: [
1180
+ /* @__PURE__ */ jsx6("p", { children: "No news found." }),
1181
+ selectedSource && /* @__PURE__ */ jsx6("p", { className: "mt-1 text-xs", children: 'Click "Scrape" to fetch latest news.' })
1182
+ ] }) : /* @__PURE__ */ jsx6(
1183
+ NewsList,
1184
+ {
1185
+ news: trendingNews.slice(0, 10),
1186
+ onView: (item) => window.open(item.sourceUrl || item.link, "_blank"),
1187
+ onRecreate: (payload) => {
1188
+ setShowNewsDropdown(false);
1189
+ onSelectNews == null ? void 0 : onSelectNews(payload);
1190
+ }
1191
+ }
1192
+ ) })
1193
+ ] })
1194
+ ] }),
1195
+ /* @__PURE__ */ jsx6(
1196
+ "textarea",
1197
+ {
1198
+ ref: textareaRef,
1199
+ value: input,
1200
+ onChange: (e) => setInput(e.target.value),
1201
+ onKeyDown: (e) => {
1202
+ if (e.key === "Enter" && !e.shiftKey) {
1203
+ e.preventDefault();
1204
+ handleSend();
1205
+ }
1206
+ },
1207
+ rows: 1,
1208
+ placeholder: "Ask AI something\u2026",
1209
+ className: `flex-1 resize-none overflow-hidden border border-gray-300 ${!showNewsPanel ? "!pl-14" : "!pl-5"} !pr-[50px] input_box_textarea`,
1210
+ style: { maxHeight: "200px", overflowY: input.split("\n").length > 6 ? "auto" : "hidden" }
1211
+ }
1212
+ ),
1213
+ /* @__PURE__ */ jsx6(
1214
+ "button",
1215
+ {
1216
+ onClick: handleSend,
1217
+ className: "flex h-10 w-10 absolute right-[10px] top-[5px] items-center justify-center rounded-full bg-emerald-600 text-white",
1218
+ style: { backgroundColor: primaryColor, color: "#fff" },
1219
+ children: /* @__PURE__ */ jsx6(SendHorizontal, { size: 18 })
1220
+ }
1221
+ )
1222
+ ] }) }),
1223
+ /* @__PURE__ */ jsx6(
1224
+ EditModal,
1225
+ {
1226
+ isOpen: editModal.isOpen,
1227
+ initialContent: editModal.content,
1228
+ metaKeywords: editModal.metaKeywords,
1229
+ onClose: handleCloseModal,
1230
+ onSaveDraft: handleSaveDraft,
1231
+ onPost: handlePost
1232
+ }
1233
+ )
1234
+ ] });
1235
+ }
1236
+
1237
+ // components/chatbot/UserMenu.tsx
1238
+ import { useEffect as useEffect5, useRef as useRef2, useState as useState5 } from "react";
1239
+ import {
1240
+ Settings,
1241
+ User,
1242
+ HelpCircle,
1243
+ LogOut,
1244
+ Palette
1245
+ } from "lucide-react";
1246
+ import toast from "react-hot-toast";
1247
+
1248
+ // services/auth.service.ts
1249
+ var logoutUser = async () => {
1250
+ const { data } = await api_default.post("/auth/logout");
1251
+ return data;
1252
+ };
1253
+
1254
+ // components/chatbot/UserMenu.tsx
1255
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1256
+ function UserMenu({
1257
+ onNavigate,
1258
+ onLogout
1259
+ }) {
1260
+ const [open, setOpen] = useState5(false);
1261
+ const ref = useRef2(null);
1262
+ useEffect5(() => {
1263
+ const handler = (e) => {
1264
+ if (ref.current && !ref.current.contains(e.target)) {
1265
+ setOpen(false);
1266
+ }
1267
+ };
1268
+ document.addEventListener("mousedown", handler);
1269
+ return () => document.removeEventListener("mousedown", handler);
1270
+ }, []);
1271
+ function go(path) {
1272
+ setOpen(false);
1273
+ onNavigate == null ? void 0 : onNavigate(path);
1274
+ }
1275
+ async function logout() {
1276
+ setOpen(false);
1277
+ if (onLogout) {
1278
+ onLogout();
1279
+ return;
1280
+ }
1281
+ try {
1282
+ await logoutUser();
1283
+ toast.success("Logged out successfully");
1284
+ onNavigate == null ? void 0 : onNavigate("/login");
1285
+ } catch (err) {
1286
+ toast.error(err || "Logout failed");
1287
+ }
1288
+ }
1289
+ return /* @__PURE__ */ jsxs6("div", { ref, className: "relative", children: [
1290
+ /* @__PURE__ */ jsx7(
1291
+ "button",
1292
+ {
1293
+ onClick: () => setOpen((v) => !v),
1294
+ className: "p-2 rounded-full hover:bg-gray-100 transition",
1295
+ "aria-label": "Settings",
1296
+ children: /* @__PURE__ */ jsx7(Settings, { size: 20, className: "text-gray-600" })
1297
+ }
1298
+ ),
1299
+ open && /* @__PURE__ */ jsxs6("div", { className: "absolute right-0 top-full mb-2 w-52 bg-white border border-gray-200 rounded-lg shadow-lg z-50", children: [
1300
+ /* @__PURE__ */ jsx7(MenuItem, { icon: User, label: "Account", onClick: () => go("/dashboard/account") }),
1301
+ /* @__PURE__ */ jsx7(MenuItem, { icon: Settings, label: "Preferences", onClick: () => go("/dashboard/preferences") }),
1302
+ /* @__PURE__ */ jsx7(MenuItem, { icon: Palette, label: "Appearance", onClick: () => go("/dashboard/appearance") }),
1303
+ /* @__PURE__ */ jsx7(MenuItem, { icon: HelpCircle, label: "Settings", onClick: () => go("/dashboard/settings") }),
1304
+ /* @__PURE__ */ jsx7(MenuItem, { icon: HelpCircle, label: "Help & Support", onClick: () => go("/dashboard/help") }),
1305
+ /* @__PURE__ */ jsx7("div", { className: "border-t border-gray-300 my-1" }),
1306
+ /* @__PURE__ */ jsx7(
1307
+ MenuItem,
1308
+ {
1309
+ icon: LogOut,
1310
+ label: "Logout",
1311
+ danger: true,
1312
+ onClick: logout
1313
+ }
1314
+ )
1315
+ ] })
1316
+ ] });
1317
+ }
1318
+ function MenuItem({
1319
+ icon: Icon,
1320
+ label,
1321
+ onClick,
1322
+ danger = false
1323
+ }) {
1324
+ return /* @__PURE__ */ jsxs6(
1325
+ "button",
1326
+ {
1327
+ onClick,
1328
+ className: `w-full flex items-center gap-2 px-4 py-2 text-sm transition ${danger ? "text-red-600 hover:bg-red-50" : "text-gray-700 hover:bg-gray-100"}`,
1329
+ children: [
1330
+ /* @__PURE__ */ jsx7(Icon, { size: 16 }),
1331
+ label
1332
+ ]
1333
+ }
1334
+ );
1335
+ }
1336
+
1337
+ // components/chatbot/headerBar.tsx
1338
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1339
+ function HeaderBar({
1340
+ onNavigate,
1341
+ onLogout
1342
+ }) {
1343
+ const { primaryColor, botName, logoUrl } = useTheme();
1344
+ return /* @__PURE__ */ jsx8("header", { className: "sticky top-0 z-40 bg-white border-b border-gray-200", children: /* @__PURE__ */ jsxs7("div", { className: "mx-auto flex h-14 items-center justify-between px-4", children: [
1345
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3 cursor-pointer", onClick: () => onNavigate == null ? void 0 : onNavigate("/"), children: [
1346
+ logoUrl ? /* @__PURE__ */ jsx8("img", { src: logoUrl, alt: "Logo", className: "h-8 w-8 rounded-md object-cover" }) : /* @__PURE__ */ jsx8(
1347
+ "div",
1348
+ {
1349
+ className: "h-8 w-8 rounded-md text-white flex items-center justify-center font-bold text-sm",
1350
+ style: { backgroundColor: primaryColor },
1351
+ children: botName.charAt(0).toUpperCase()
1352
+ }
1353
+ ),
1354
+ /* @__PURE__ */ jsx8("span", { className: "font-semibold text-gray-900 text-base", children: botName.toUpperCase() })
1355
+ ] }),
1356
+ /* @__PURE__ */ jsx8("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsx8(UserMenu, { onNavigate, onLogout }) })
1357
+ ] }) });
1358
+ }
1359
+
1360
+ // components/news/TrendingNews.tsx
1361
+ import { useEffect as useEffect6, useState as useState6, useCallback } from "react";
1362
+ import toast2 from "react-hot-toast";
1363
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1364
+ function TrendingNews({
1365
+ onRecreate,
1366
+ selectedSource,
1367
+ refreshKey,
1368
+ news: externalNews,
1369
+ isLoading: externalLoading
1370
+ }) {
1371
+ const [news, setNews] = useState6([]);
1372
+ const [loading, setLoading] = useState6(false);
1373
+ const displayNews = externalNews !== void 0 ? externalNews : news;
1374
+ const isLoading = externalLoading !== void 0 ? externalLoading : loading;
1375
+ const fetchNews = useCallback(async () => {
1376
+ if (externalNews !== void 0) {
1377
+ return;
1378
+ }
1379
+ setLoading(true);
1380
+ try {
1381
+ let data;
1382
+ if (selectedSource) {
1383
+ data = await getNewsBySource(selectedSource);
1384
+ } else {
1385
+ data = await getTrendingNews();
1386
+ }
1387
+ setNews(data || []);
1388
+ } catch (e) {
1389
+ toast2.error("Failed to load news");
1390
+ } finally {
1391
+ setLoading(false);
1392
+ }
1393
+ }, [selectedSource, externalNews]);
1394
+ useEffect6(() => {
1395
+ fetchNews();
1396
+ }, [fetchNews, refreshKey]);
1397
+ function handleView(item) {
1398
+ window.open(item.sourceUrl || item.link, "_blank");
1399
+ }
1400
+ if (isLoading) {
1401
+ return /* @__PURE__ */ jsx9("div", { className: "p-4 text-sm text-gray-500", children: "Loading news..." });
1402
+ }
1403
+ if (!displayNews || displayNews.length === 0) {
1404
+ return /* @__PURE__ */ jsxs8("div", { className: "p-4 text-sm text-gray-500 text-center", children: [
1405
+ /* @__PURE__ */ jsx9("p", { children: "No news found for this source." }),
1406
+ /* @__PURE__ */ jsx9("p", { className: "mt-1 text-xs", children: 'Click "Scrape" to fetch latest news.' })
1407
+ ] });
1408
+ }
1409
+ return /* @__PURE__ */ jsx9(
1410
+ NewsList,
1411
+ {
1412
+ news: displayNews,
1413
+ onView: handleView,
1414
+ onRecreate
1415
+ }
1416
+ );
1417
+ }
1418
+
1419
+ // components/news/SourceSelector.tsx
1420
+ import { useEffect as useEffect7, useState as useState7, useCallback as useCallback2 } from "react";
1421
+ import { RefreshCcw as RefreshCcw3 } from "lucide-react";
1422
+ import Select2 from "react-select";
1423
+ import toast3 from "react-hot-toast";
1424
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1425
+ var ALL_SOURCES_VALUE = "__all__";
1426
+ function SourceSelector({
1427
+ selectedSource,
1428
+ onSourceChange,
1429
+ onScrapeComplete,
1430
+ onNewsLoaded,
1431
+ onLoadingChange
1432
+ }) {
1433
+ const [sources, setSources] = useState7([]);
1434
+ const [loading, setLoading] = useState7(true);
1435
+ const [scraping, setScraping] = useState7(false);
1436
+ const [fetchingNews, setFetchingNews] = useState7(true);
1437
+ const { primaryColor } = useTheme();
1438
+ useEffect7(() => {
1439
+ onLoadingChange == null ? void 0 : onLoadingChange(fetchingNews);
1440
+ }, [fetchingNews, onLoadingChange]);
1441
+ useEffect7(() => {
1442
+ const fetchSources = async () => {
1443
+ try {
1444
+ const data = await getNewsSources();
1445
+ setSources(data || []);
1446
+ } catch (e) {
1447
+ toast3.error("Failed to load news sources");
1448
+ } finally {
1449
+ setLoading(false);
1450
+ }
1451
+ };
1452
+ fetchSources();
1453
+ }, []);
1454
+ const fetchNews = useCallback2(async (sourceId) => {
1455
+ setFetchingNews(true);
1456
+ try {
1457
+ let news;
1458
+ if (sourceId) {
1459
+ news = await getNewsBySource(sourceId);
1460
+ } else {
1461
+ news = await getTrendingNews();
1462
+ }
1463
+ onNewsLoaded == null ? void 0 : onNewsLoaded(news || []);
1464
+ } catch (err) {
1465
+ console.error("Failed to fetch news:", err);
1466
+ } finally {
1467
+ setFetchingNews(false);
1468
+ }
1469
+ }, []);
1470
+ useEffect7(() => {
1471
+ fetchNews(selectedSource);
1472
+ }, [selectedSource, fetchNews]);
1473
+ const handleSourceSelect = (option) => {
1474
+ var _a;
1475
+ const value = (option == null ? void 0 : option.value) === ALL_SOURCES_VALUE ? null : (_a = option == null ? void 0 : option.value) != null ? _a : null;
1476
+ onSourceChange(value);
1477
+ };
1478
+ const handleScrape = async () => {
1479
+ if (!selectedSource) {
1480
+ toast3.error("Please select a source first");
1481
+ return;
1482
+ }
1483
+ setScraping(true);
1484
+ try {
1485
+ await scrapeNewsSource(selectedSource);
1486
+ toast3.success("News scraped successfully!");
1487
+ onScrapeComplete == null ? void 0 : onScrapeComplete();
1488
+ const news = await getNewsBySource(selectedSource);
1489
+ onNewsLoaded == null ? void 0 : onNewsLoaded(news || []);
1490
+ } catch (err) {
1491
+ toast3.error(err || "Failed to scrape news");
1492
+ } finally {
1493
+ setScraping(false);
1494
+ }
1495
+ };
1496
+ const options = [
1497
+ { value: ALL_SOURCES_VALUE, label: "All Sources (Trending)" },
1498
+ ...sources.map((source) => ({
1499
+ value: source.id,
1500
+ label: source.name
1501
+ }))
1502
+ ];
1503
+ const selectedOption = options.find(
1504
+ (opt) => selectedSource === null ? opt.value === ALL_SOURCES_VALUE : opt.value === selectedSource
1505
+ ) || options[0];
1506
+ return /* @__PURE__ */ jsxs9("div", { className: "px-3 py-2 border-b border-gray-100 flex items-center gap-2", children: [
1507
+ /* @__PURE__ */ jsx10("div", { className: "flex-1 min-w-[180px]", children: /* @__PURE__ */ jsx10(
1508
+ Select2,
1509
+ {
1510
+ options,
1511
+ value: selectedOption,
1512
+ onChange: handleSourceSelect,
1513
+ isLoading: loading,
1514
+ isDisabled: loading,
1515
+ placeholder: "Select source...",
1516
+ classNamePrefix: "react-select",
1517
+ menuPlacement: "bottom",
1518
+ menuPosition: "fixed",
1519
+ menuShouldScrollIntoView: false,
1520
+ maxMenuHeight: 220,
1521
+ menuPortalTarget: typeof window !== "undefined" ? document.body : null,
1522
+ styles: {
1523
+ container: (base) => __spreadProps(__spreadValues({}, base), {
1524
+ width: "100%"
1525
+ }),
1526
+ control: (base) => __spreadProps(__spreadValues({}, base), {
1527
+ minHeight: "38px",
1528
+ borderColor: "#e5e7eb",
1529
+ boxShadow: "none",
1530
+ width: "100%"
1531
+ }),
1532
+ menu: (base) => __spreadProps(__spreadValues({}, base), {
1533
+ width: "100%",
1534
+ zIndex: 999999
1535
+ }),
1536
+ menuPortal: (base) => __spreadProps(__spreadValues({}, base), {
1537
+ zIndex: 999999
1538
+ }),
1539
+ option: (base, state) => __spreadProps(__spreadValues({}, base), {
1540
+ backgroundColor: state.isSelected ? primaryColor : state.isFocused ? "#f3f4f6" : "white",
1541
+ color: state.isSelected ? "white" : "#374151",
1542
+ cursor: "pointer"
1543
+ })
1544
+ }
1545
+ }
1546
+ ) }),
1547
+ selectedSource && /* @__PURE__ */ jsxs9(
1548
+ "button",
1549
+ {
1550
+ onClick: handleScrape,
1551
+ disabled: scraping,
1552
+ className: "flex items-center gap-1.5 px-3 py-2 bg-emerald-600 text-white rounded-lg text-sm font-medium hover:bg-emerald-700 transition disabled:opacity-50",
1553
+ title: "Fetch latest news",
1554
+ children: [
1555
+ /* @__PURE__ */ jsx10(RefreshCcw3, { size: 14, className: scraping ? "animate-spin" : "" }),
1556
+ scraping ? "Scraping..." : "Scrape"
1557
+ ]
1558
+ }
1559
+ ),
1560
+ !selectedSource && /* @__PURE__ */ jsxs9(
1561
+ "button",
1562
+ {
1563
+ onClick: () => fetchNews(null),
1564
+ disabled: fetchingNews,
1565
+ className: "flex items-center gap-1 px-3 py-2 text-sm text-gray-600 hover:text-gray-900 border border-gray-200 rounded-lg transition",
1566
+ children: [
1567
+ /* @__PURE__ */ jsx10(RefreshCcw3, { size: 14, className: fetchingNews ? "animate-spin" : "" }),
1568
+ "Refresh"
1569
+ ]
1570
+ }
1571
+ )
1572
+ ] });
1573
+ }
1574
+
1575
+ // services/chat.service.ts
1576
+ var analyzeInputApi = async (input) => {
1577
+ const { data } = await api_default.post("/chat/analyze-input", { input });
1578
+ return data.data;
1579
+ };
1580
+ var createContentApi = async (payload) => {
1581
+ const { data } = await api_default.post("/chat/create-content", payload);
1582
+ return data.data;
1583
+ };
1584
+ var createContentStreamApi = async ({
1585
+ url,
1586
+ content,
1587
+ actionId,
1588
+ settings,
1589
+ onChunk,
1590
+ onComplete,
1591
+ onError
1592
+ }) => {
1593
+ var _a;
1594
+ const API_BASE_URL = getApiBaseUrl();
1595
+ const apiKey = process.env.NEXT_PUBLIC_API_KEY;
1596
+ const headers = {
1597
+ "Content-Type": "application/json"
1598
+ };
1599
+ if (apiKey) {
1600
+ headers["x-api-key"] = apiKey;
1601
+ }
1602
+ const response = await fetch(`${API_BASE_URL}/chat/create-content/stream`, {
1603
+ method: "POST",
1604
+ headers,
1605
+ credentials: "include",
1606
+ body: JSON.stringify({ url, content, actionId, settings })
1607
+ });
1608
+ if (!response.ok) {
1609
+ const errorText = await response.text();
1610
+ throw new Error(`HTTP error! status: ${response.status} - ${errorText}`);
1611
+ }
1612
+ const reader = (_a = response.body) == null ? void 0 : _a.getReader();
1613
+ const decoder = new TextDecoder();
1614
+ if (!reader) {
1615
+ throw new Error("No reader available");
1616
+ }
1617
+ let buffer = "";
1618
+ let hasReceivedData = false;
1619
+ while (true) {
1620
+ const { done, value } = await reader.read();
1621
+ if (done) {
1622
+ if (hasReceivedData) onComplete == null ? void 0 : onComplete();
1623
+ break;
1624
+ }
1625
+ const chunk = decoder.decode(value, { stream: true });
1626
+ buffer += chunk;
1627
+ const lines = buffer.split("\n");
1628
+ buffer = lines.pop() || "";
1629
+ for (const line of lines) {
1630
+ const trimmedLine = line.trim();
1631
+ if (trimmedLine === "") continue;
1632
+ hasReceivedData = true;
1633
+ if (trimmedLine.startsWith("data: ")) {
1634
+ const data = trimmedLine.slice(6).trim();
1635
+ if (data === "[DONE]") {
1636
+ onComplete == null ? void 0 : onComplete();
1637
+ return;
1638
+ }
1639
+ try {
1640
+ const parsed = JSON.parse(data);
1641
+ if (parsed.content) onChunk(parsed.content);
1642
+ else if (parsed.delta) onChunk(parsed.delta);
1643
+ else if (parsed.text) onChunk(parsed.text);
1644
+ else if (parsed.chunk) onChunk(parsed.chunk);
1645
+ else if (typeof parsed === "string") onChunk(parsed);
1646
+ } catch (e) {
1647
+ if (data) onChunk(data);
1648
+ }
1649
+ } else if (trimmedLine) {
1650
+ onChunk(trimmedLine + "\n");
1651
+ }
1652
+ }
1653
+ }
1654
+ if (!hasReceivedData) {
1655
+ throw new Error("No data received from stream");
1656
+ }
1657
+ };
1658
+ var rewriteNewsStreamApi = async ({
1659
+ article,
1660
+ language = "English",
1661
+ articleId,
1662
+ tone,
1663
+ style,
1664
+ wordCount,
1665
+ includeQuotes,
1666
+ includeFAQ,
1667
+ targetAudience,
1668
+ onChunk,
1669
+ onComplete,
1670
+ onError
1671
+ }) => {
1672
+ var _a;
1673
+ const payload = {
1674
+ article,
1675
+ language
1676
+ };
1677
+ if (articleId) {
1678
+ payload.articleId = articleId;
1679
+ }
1680
+ if (tone) payload.tone = tone;
1681
+ if (style) payload.style = style;
1682
+ if (wordCount) payload.wordCount = wordCount;
1683
+ if (includeQuotes !== void 0) payload.includeQuotes = includeQuotes;
1684
+ if (includeFAQ !== void 0) payload.includeFAQ = includeFAQ;
1685
+ if (targetAudience) payload.targetAudience = targetAudience;
1686
+ try {
1687
+ const API_BASE_URL = getApiBaseUrl();
1688
+ const apiKey = process.env.NEXT_PUBLIC_API_KEY;
1689
+ console.log("\u{1F680} Starting stream request to:", `${API_BASE_URL}/chat/rewrite/stream`);
1690
+ console.log("\u{1F4E6} Payload:", payload);
1691
+ const headers = {
1692
+ "Content-Type": "application/json"
1693
+ };
1694
+ if (apiKey) {
1695
+ headers["x-api-key"] = apiKey;
1696
+ }
1697
+ const response = await fetch(`${API_BASE_URL}/chat/rewrite/stream`, {
1698
+ method: "POST",
1699
+ headers,
1700
+ credentials: "include",
1701
+ // Include cookies for authentication
1702
+ body: JSON.stringify(payload)
1703
+ });
1704
+ console.log("\u{1F4E1} Response status:", response.status);
1705
+ console.log("\u{1F4E1} Response headers:", Object.fromEntries(response.headers.entries()));
1706
+ if (!response.ok) {
1707
+ const errorText = await response.text();
1708
+ console.error("\u274C API Error:", response.status, errorText);
1709
+ throw new Error(`HTTP error! status: ${response.status} - ${errorText}`);
1710
+ }
1711
+ const reader = (_a = response.body) == null ? void 0 : _a.getReader();
1712
+ const decoder = new TextDecoder();
1713
+ if (!reader) {
1714
+ throw new Error("No reader available");
1715
+ }
1716
+ let buffer = "";
1717
+ let hasReceivedData = false;
1718
+ while (true) {
1719
+ const { done, value } = await reader.read();
1720
+ if (done) {
1721
+ if (hasReceivedData) {
1722
+ onComplete == null ? void 0 : onComplete();
1723
+ }
1724
+ break;
1725
+ }
1726
+ const chunk = decoder.decode(value, { stream: true });
1727
+ buffer += chunk;
1728
+ const lines = buffer.split("\n");
1729
+ buffer = lines.pop() || "";
1730
+ for (const line of lines) {
1731
+ const trimmedLine = line.trim();
1732
+ if (trimmedLine === "") continue;
1733
+ hasReceivedData = true;
1734
+ console.log("\u{1F4E8} Received line:", trimmedLine.substring(0, 100) + (trimmedLine.length > 100 ? "..." : ""));
1735
+ if (trimmedLine.startsWith("data: ")) {
1736
+ const data = trimmedLine.slice(6).trim();
1737
+ if (data === "[DONE]") {
1738
+ console.log("\u2705 Stream completed with [DONE] signal");
1739
+ onComplete == null ? void 0 : onComplete();
1740
+ return;
1741
+ }
1742
+ try {
1743
+ const parsed = JSON.parse(data);
1744
+ console.log("\u{1F4CB} Parsed JSON:", parsed);
1745
+ if (parsed.content) {
1746
+ onChunk(parsed.content);
1747
+ } else if (parsed.delta) {
1748
+ onChunk(parsed.delta);
1749
+ } else if (parsed.text) {
1750
+ onChunk(parsed.text);
1751
+ } else if (parsed.chunk) {
1752
+ onChunk(parsed.chunk);
1753
+ } else if (typeof parsed === "string") {
1754
+ onChunk(parsed);
1755
+ } else {
1756
+ console.warn("\u26A0\uFE0F Unknown JSON format:", parsed);
1757
+ }
1758
+ } catch (e) {
1759
+ console.log("\u{1F4DD} Non-JSON data, treating as plain text");
1760
+ if (data) {
1761
+ onChunk(data);
1762
+ }
1763
+ }
1764
+ } else {
1765
+ console.log("\u{1F4C4} Plain text chunk");
1766
+ if (trimmedLine) {
1767
+ onChunk(trimmedLine + "\n");
1768
+ }
1769
+ }
1770
+ }
1771
+ }
1772
+ if (!hasReceivedData) {
1773
+ console.error("\u274C No data received from stream");
1774
+ throw new Error("No data received from stream");
1775
+ }
1776
+ console.log("\u2705 Stream completed successfully");
1777
+ } catch (error) {
1778
+ console.error("\u274C Streaming error:", error);
1779
+ console.error("Error details:", {
1780
+ message: error.message,
1781
+ name: error.name,
1782
+ stack: error.stack
1783
+ });
1784
+ onError == null ? void 0 : onError(error);
1785
+ throw error;
1786
+ }
1787
+ };
1788
+ var rewriteNewsApi = async ({
1789
+ article,
1790
+ language = "English",
1791
+ articleId,
1792
+ tone,
1793
+ style,
1794
+ wordCount,
1795
+ includeQuotes,
1796
+ includeFAQ,
1797
+ targetAudience
1798
+ }) => {
1799
+ const payload = {
1800
+ article,
1801
+ language
1802
+ };
1803
+ if (articleId) {
1804
+ payload.articleId = articleId;
1805
+ }
1806
+ if (tone) payload.tone = tone;
1807
+ if (style) payload.style = style;
1808
+ if (wordCount) payload.wordCount = wordCount;
1809
+ if (includeQuotes !== void 0) payload.includeQuotes = includeQuotes;
1810
+ if (includeFAQ !== void 0) payload.includeFAQ = includeFAQ;
1811
+ if (targetAudience) payload.targetAudience = targetAudience;
1812
+ const { data } = await api_default.post("/chat/rewrite", payload);
1813
+ return data.data;
1814
+ };
1815
+
1816
+ // components/chatbot/ChatBot.tsx
1817
+ import toast4 from "react-hot-toast";
1818
+ import { Loader2 } from "lucide-react";
1819
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1820
+ function ChatBot({
1821
+ onNavigate,
1822
+ onLogout
1823
+ } = {}) {
1824
+ const { loading, showNewsPanel } = useTheme();
1825
+ const { preferences } = usePreferences();
1826
+ const [selectedSource, setSelectedSource] = useState8(null);
1827
+ const [news, setNews] = useState8([]);
1828
+ const [newsLoading, setNewsLoading] = useState8(true);
1829
+ const [selectedArticle, setSelectedArticle] = useState8(null);
1830
+ const [messages, setMessages] = useState8([]);
1831
+ const [showChatMobile, setShowChatMobile] = useState8(false);
1832
+ const [isStreaming, setIsStreaming] = useState8(false);
1833
+ const [analyzedData, setAnalyzedData] = useState8(null);
1834
+ const handleNewsLoaded = useCallback3((loadedNews) => {
1835
+ setNews(loadedNews);
1836
+ }, []);
1837
+ const handleLoadingChange = useCallback3((isLoading) => {
1838
+ setNewsLoading(isLoading);
1839
+ }, []);
1840
+ const handleRecreate = async ({ title, content, id }) => {
1841
+ var _a;
1842
+ setShowChatMobile(true);
1843
+ const assistantId = crypto.randomUUID();
1844
+ setMessages((prev) => [
1845
+ ...prev,
1846
+ {
1847
+ id: crypto.randomUUID(),
1848
+ role: "user",
1849
+ content: `Recreate this news:
1850
+ ${title}`
1851
+ },
1852
+ {
1853
+ id: assistantId,
1854
+ role: "assistant",
1855
+ content: "\u23F3 Creating article..."
1856
+ }
1857
+ ]);
1858
+ try {
1859
+ let accumulatedContent = "";
1860
+ let hasStartedStreaming = false;
1861
+ const contentPrefs = preferences == null ? void 0 : preferences.content;
1862
+ const lang = ((_a = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _a.language) === "hi" ? "Hindi" : "English";
1863
+ try {
1864
+ await rewriteNewsStreamApi({
1865
+ article: content,
1866
+ language: lang,
1867
+ articleId: id,
1868
+ tone: contentPrefs == null ? void 0 : contentPrefs.tone,
1869
+ style: contentPrefs == null ? void 0 : contentPrefs.style,
1870
+ wordCount: contentPrefs == null ? void 0 : contentPrefs.wordCount,
1871
+ includeQuotes: contentPrefs == null ? void 0 : contentPrefs.includeQuotes,
1872
+ includeFAQ: contentPrefs == null ? void 0 : contentPrefs.includeFAQ,
1873
+ targetAudience: contentPrefs == null ? void 0 : contentPrefs.targetAudience,
1874
+ onChunk: (chunk) => {
1875
+ hasStartedStreaming = true;
1876
+ accumulatedContent += chunk;
1877
+ setMessages(
1878
+ (prev) => prev.map(
1879
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent }) : m
1880
+ )
1881
+ );
1882
+ },
1883
+ onComplete: () => {
1884
+ console.log("Streaming completed successfully");
1885
+ toast4.success("Article created successfully!");
1886
+ },
1887
+ onError: async (error) => {
1888
+ console.error("Streaming error:", error);
1889
+ if (!hasStartedStreaming) {
1890
+ console.log("Falling back to regular API...");
1891
+ throw error;
1892
+ } else {
1893
+ toast4.error("Failed to complete article generation");
1894
+ setMessages(
1895
+ (prev) => prev.map(
1896
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent || "\u274C Failed to create article. Please try again." }) : m
1897
+ )
1898
+ );
1899
+ }
1900
+ }
1901
+ });
1902
+ } catch (streamError) {
1903
+ console.log("Streaming failed, using regular API...", streamError);
1904
+ setMessages(
1905
+ (prev) => prev.map(
1906
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u23F3 Generating with regular API..." }) : m
1907
+ )
1908
+ );
1909
+ const result = await rewriteNewsApi({
1910
+ article: content,
1911
+ language: lang,
1912
+ articleId: id,
1913
+ tone: contentPrefs == null ? void 0 : contentPrefs.tone,
1914
+ style: contentPrefs == null ? void 0 : contentPrefs.style,
1915
+ wordCount: contentPrefs == null ? void 0 : contentPrefs.wordCount,
1916
+ includeQuotes: contentPrefs == null ? void 0 : contentPrefs.includeQuotes,
1917
+ includeFAQ: contentPrefs == null ? void 0 : contentPrefs.includeFAQ,
1918
+ targetAudience: contentPrefs == null ? void 0 : contentPrefs.targetAudience
1919
+ });
1920
+ setMessages(
1921
+ (prev) => prev.map(
1922
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: result.article || result }) : m
1923
+ )
1924
+ );
1925
+ toast4.success("Article created successfully!");
1926
+ }
1927
+ } catch (err) {
1928
+ console.error("Complete Error:", err);
1929
+ toast4.error((err == null ? void 0 : err.message) || "An error occurred while creating the article");
1930
+ setMessages(
1931
+ (prev) => prev.map(
1932
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to create article. Please try again." }) : m
1933
+ )
1934
+ );
1935
+ }
1936
+ };
1937
+ const handleSendMessage = async (text) => {
1938
+ var _a, _b;
1939
+ const userMsgId = crypto.randomUUID();
1940
+ const assistantId = crypto.randomUUID();
1941
+ setMessages((prev) => [
1942
+ ...prev,
1943
+ { id: userMsgId, role: "user", content: text }
1944
+ ]);
1945
+ const urlRegex = /https?:\/\/[^\s]+/;
1946
+ const hasUrl = urlRegex.test(text);
1947
+ if (hasUrl) {
1948
+ setMessages((prev) => [
1949
+ ...prev,
1950
+ { id: assistantId, role: "assistant", content: "\u{1F50D} Analyzing your link..." }
1951
+ ]);
1952
+ try {
1953
+ const result = await analyzeInputApi(text);
1954
+ if (result.hasUrl && ((_a = result.options) == null ? void 0 : _a.length) > 0) {
1955
+ setAnalyzedData({
1956
+ url: result.url || "",
1957
+ content: result.content || "",
1958
+ options: result.options,
1959
+ messageId: assistantId
1960
+ });
1961
+ const optionsList = result.options.map((opt) => `\u2022 **${opt.name}**${opt.description ? ` \u2013 ${opt.description}` : ""}`).join("\n");
1962
+ setMessages(
1963
+ (prev) => prev.map(
1964
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), {
1965
+ content: `I found an article (${result.wordCount || 0} words). What would you like to do?
1966
+
1967
+ ${optionsList}`
1968
+ }) : m
1969
+ )
1970
+ );
1971
+ } else {
1972
+ setMessages(
1973
+ (prev) => prev.map(
1974
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "Could not extract content from that URL. Please try a different link." }) : m
1975
+ )
1976
+ );
1977
+ }
1978
+ } catch (err) {
1979
+ console.error("Analyze input error:", err);
1980
+ toast4.error("Failed to analyze the link");
1981
+ setMessages(
1982
+ (prev) => prev.map(
1983
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to analyze the link. Please try again." }) : m
1984
+ )
1985
+ );
1986
+ }
1987
+ } else {
1988
+ setMessages((prev) => [
1989
+ ...prev,
1990
+ { id: assistantId, role: "assistant", content: "\u23F3 Generating content..." }
1991
+ ]);
1992
+ setIsStreaming(true);
1993
+ try {
1994
+ const contentPrefs = preferences == null ? void 0 : preferences.content;
1995
+ const lang = ((_b = preferences == null ? void 0 : preferences.localization) == null ? void 0 : _b.language) === "hi" ? "Hindi" : "English";
1996
+ let accumulatedContent = "";
1997
+ await rewriteNewsStreamApi({
1998
+ article: text,
1999
+ language: lang,
2000
+ tone: contentPrefs == null ? void 0 : contentPrefs.tone,
2001
+ style: contentPrefs == null ? void 0 : contentPrefs.style,
2002
+ wordCount: contentPrefs == null ? void 0 : contentPrefs.wordCount,
2003
+ includeQuotes: contentPrefs == null ? void 0 : contentPrefs.includeQuotes,
2004
+ includeFAQ: contentPrefs == null ? void 0 : contentPrefs.includeFAQ,
2005
+ targetAudience: contentPrefs == null ? void 0 : contentPrefs.targetAudience,
2006
+ onChunk: (chunk) => {
2007
+ accumulatedContent += chunk;
2008
+ setMessages(
2009
+ (prev) => prev.map(
2010
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent }) : m
2011
+ )
2012
+ );
2013
+ },
2014
+ onComplete: () => {
2015
+ setIsStreaming(false);
2016
+ toast4.success("Content generated!");
2017
+ },
2018
+ onError: (error) => {
2019
+ console.error("Stream error:", error);
2020
+ setIsStreaming(false);
2021
+ toast4.error("Failed to generate content");
2022
+ }
2023
+ });
2024
+ } catch (err) {
2025
+ console.error("Send message error:", err);
2026
+ setIsStreaming(false);
2027
+ setMessages(
2028
+ (prev) => prev.map(
2029
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to generate content. Please try again." }) : m
2030
+ )
2031
+ );
2032
+ }
2033
+ }
2034
+ };
2035
+ const handleSelectAction = async (actionId, url, content) => {
2036
+ var _a;
2037
+ const assistantId = crypto.randomUUID();
2038
+ setAnalyzedData(null);
2039
+ const actionName = ((_a = analyzedData == null ? void 0 : analyzedData.options.find((o) => o.id === actionId)) == null ? void 0 : _a.name) || actionId;
2040
+ setMessages((prev) => [
2041
+ ...prev,
2042
+ { id: crypto.randomUUID(), role: "user", content: `Action: ${actionName}` },
2043
+ { id: assistantId, role: "assistant", content: "\u23F3 Creating content..." }
2044
+ ]);
2045
+ setIsStreaming(true);
2046
+ try {
2047
+ const contentPrefs = preferences == null ? void 0 : preferences.content;
2048
+ let accumulatedContent = "";
2049
+ try {
2050
+ await createContentStreamApi({
2051
+ url,
2052
+ content,
2053
+ actionId,
2054
+ settings: {
2055
+ tone: contentPrefs == null ? void 0 : contentPrefs.tone,
2056
+ style: contentPrefs == null ? void 0 : contentPrefs.style,
2057
+ wordCount: contentPrefs == null ? void 0 : contentPrefs.wordCount
2058
+ },
2059
+ onChunk: (chunk) => {
2060
+ accumulatedContent += chunk;
2061
+ setMessages(
2062
+ (prev) => prev.map(
2063
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: accumulatedContent }) : m
2064
+ )
2065
+ );
2066
+ },
2067
+ onComplete: () => {
2068
+ setIsStreaming(false);
2069
+ toast4.success("Content created!");
2070
+ },
2071
+ onError: (error) => {
2072
+ console.error("Stream error:", error);
2073
+ setIsStreaming(false);
2074
+ toast4.error("Failed to create content");
2075
+ }
2076
+ });
2077
+ } catch (e) {
2078
+ const result = await createContentApi({ url, content, actionId, settings: {
2079
+ tone: contentPrefs == null ? void 0 : contentPrefs.tone,
2080
+ style: contentPrefs == null ? void 0 : contentPrefs.style,
2081
+ wordCount: contentPrefs == null ? void 0 : contentPrefs.wordCount
2082
+ } });
2083
+ setMessages(
2084
+ (prev) => prev.map(
2085
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: result.article || result.content || JSON.stringify(result) }) : m
2086
+ )
2087
+ );
2088
+ setIsStreaming(false);
2089
+ toast4.success("Content created!");
2090
+ }
2091
+ } catch (err) {
2092
+ console.error("Create content error:", err);
2093
+ setIsStreaming(false);
2094
+ setMessages(
2095
+ (prev) => prev.map(
2096
+ (m) => m.id === assistantId ? __spreadProps(__spreadValues({}, m), { content: "\u274C Failed to create content. Please try again." }) : m
2097
+ )
2098
+ );
2099
+ }
2100
+ };
2101
+ if (loading) {
2102
+ return /* @__PURE__ */ jsx11("div", { className: "w-full h-screen flex items-center justify-center bg-white", children: /* @__PURE__ */ jsxs10("div", { className: "flex flex-col items-center gap-3", children: [
2103
+ /* @__PURE__ */ jsx11(Loader2, { className: "h-8 w-8 animate-spin text-gray-400" }),
2104
+ /* @__PURE__ */ jsx11("p", { className: "text-sm text-gray-500", children: "Loading..." })
2105
+ ] }) });
2106
+ }
2107
+ return (
2108
+ // ✅ FULL SCREEN
2109
+ /* @__PURE__ */ jsxs10("div", { className: "w-full h-screen flex flex-col bg-white", children: [
2110
+ /* @__PURE__ */ jsx11(HeaderBar, { onNavigate, onLogout }),
2111
+ /* @__PURE__ */ jsxs10("div", { className: `flex-1 min-h-0 md:grid ${showNewsPanel ? "md:grid-cols-12" : ""}`, children: [
2112
+ showNewsPanel && /* @__PURE__ */ jsxs10("aside", { className: "relative col-span-4 bg-gray-50/60 border-r border-gray-300 h-[90vh] overflow-y-auto", children: [
2113
+ /* @__PURE__ */ jsx11("div", { className: "", children: /* @__PURE__ */ jsx11(
2114
+ SourceSelector,
2115
+ {
2116
+ selectedSource,
2117
+ onSourceChange: (value) => {
2118
+ console.log("Selected source:", value);
2119
+ setSelectedSource(value);
2120
+ },
2121
+ onNewsLoaded: handleNewsLoaded,
2122
+ onLoadingChange: handleLoadingChange
2123
+ }
2124
+ ) }),
2125
+ /* @__PURE__ */ jsx11(
2126
+ TrendingNews,
2127
+ {
2128
+ onRecreate: handleRecreate,
2129
+ news,
2130
+ isLoading: newsLoading
2131
+ }
2132
+ )
2133
+ ] }),
2134
+ /* @__PURE__ */ jsxs10(
2135
+ "section",
2136
+ {
2137
+ className: `
2138
+ ${showNewsPanel ? "md:col-span-8" : "w-full"} bg-white flex flex-col h-full relative
2139
+ ${showChatMobile ? "block" : "hidden md:block"}
2140
+ `,
2141
+ children: [
2142
+ /* @__PURE__ */ jsx11("div", { className: "md:hidden border-b border-gray-300 p-3", children: /* @__PURE__ */ jsx11(
2143
+ "button",
2144
+ {
2145
+ onClick: () => setShowChatMobile(false),
2146
+ className: "text-sm text-gray-600",
2147
+ children: "\u2190 Back to news"
2148
+ }
2149
+ ) }),
2150
+ /* @__PURE__ */ jsx11("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsx11(
2151
+ ChatWindow,
2152
+ {
2153
+ messages,
2154
+ onSend: handleSendMessage,
2155
+ onSelectNews: handleRecreate,
2156
+ isStreaming,
2157
+ analyzedData,
2158
+ onSelectAction: handleSelectAction
2159
+ }
2160
+ ) }),
2161
+ !messages.length && /* @__PURE__ */ jsx11("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center text-center text-gray-400 text-sm px-4", children: /* @__PURE__ */ jsxs10("div", { children: [
2162
+ /* @__PURE__ */ jsx11("p", { className: "font-medium", children: "AI News Assistant" }),
2163
+ /* @__PURE__ */ jsx11("p", { className: "mt-1", children: "Select a news article or type a message to begin" })
2164
+ ] }) })
2165
+ ]
2166
+ }
2167
+ )
2168
+ ] }),
2169
+ selectedArticle && /* @__PURE__ */ jsx11(
2170
+ ArticleModal,
2171
+ {
2172
+ article: selectedArticle,
2173
+ onClose: () => setSelectedArticle(null),
2174
+ onRecreate: handleRecreate
2175
+ }
2176
+ )
2177
+ ] })
2178
+ );
2179
+ }
2180
+
2181
+ // src/index.tsx
2182
+ import { jsx as jsx12 } from "react/jsx-runtime";
2183
+ function ContenifyChatBot({ onNavigate, onLogout }) {
2184
+ return /* @__PURE__ */ jsx12(PreferencesProvider, { children: /* @__PURE__ */ jsx12(ChatBot, { onNavigate, onLogout }) });
2185
+ }
2186
+ var index_default = ContenifyChatBot;
2187
+ export {
2188
+ ContenifyChatBot,
2189
+ index_default as default
2190
+ };
2191
+ //# sourceMappingURL=index.mjs.map