@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/README.md +36 -0
- package/dist/index.d.mts +80 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +2209 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2191 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles.css +110 -0
- package/package.json +75 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../contexts/PreferencesContext.tsx","../lib/api.ts","../lib/config.ts","../services/preferences.service.ts","../components/chatbot/ChatBot.tsx","../components/chatbot/ArticleModal.tsx","../util/util.ts","../components/chatbot/ChatWindow.tsx","../components/chatbot/EditModal.tsx","../components/chatbot/RichTextEditor.tsx","../hooks/useTheme.ts","../components/news/NewsList.tsx","../services/news.service.ts","../components/chatbot/UserMenu.tsx","../services/auth.service.ts","../components/chatbot/headerBar.tsx","../components/news/TrendingNews.tsx","../components/news/SourceSelector.tsx","../services/chat.service.ts","../src/index.tsx"],"sourcesContent":["'use client'\nimport { createContext, useContext, useState, useEffect, ReactNode } from 'react'\nimport { getMyPreferencesApi } from '@/services/preferences.service'\nimport { getServerBaseUrl } from '@/lib/config'\n\nexport interface ChatbotPreferences {\n name: string\n logoUrl?: string\n primaryColor: string\n secondaryColor: string\n theme: 'light' | 'dark' | 'system'\n}\n\nexport interface LocalizationPreferences {\n country: string\n state: string\n cities: string[]\n language: string\n locale: string\n timezone: string\n}\n\nexport interface AppearancePreferences {\n showSidebar: boolean\n showHeader: boolean\n activeThemePreset: string | null\n showNewsPanel: boolean\n}\n\nexport interface ContentPreferences {\n tone: 'formal' | 'casual' | 'engaging' | 'professional'\n style: 'news' | 'blog' | 'editorial' | 'summary'\n wordCount: 'short' | 'medium' | 'long'\n includeQuotes: boolean\n includeFAQ: boolean\n targetAudience: string\n}\n\nexport interface Preferences {\n chatbot: ChatbotPreferences\n localization: LocalizationPreferences\n appearance: AppearancePreferences\n content: ContentPreferences\n _id?: string\n user?: string\n isActive?: boolean\n createdAt?: string\n updatedAt?: string\n}\n\ninterface PreferencesContextType {\n preferences: Preferences | null\n loading: boolean\n error: string | null\n refreshPreferences: () => Promise<void>\n updatePreferences: (newPreferences: Preferences) => void\n}\n\nconst defaultPreferences: Preferences = {\n chatbot: {\n name: 'AI News Assistant',\n primaryColor: '#10b981',\n secondaryColor: '#064e3b',\n theme: 'system',\n },\n localization: {\n country: 'India',\n state: 'Uttar Pradesh',\n cities: [],\n language: 'en',\n locale: 'en-IN',\n timezone: 'Asia/Kolkata',\n },\n appearance: {\n showSidebar: true,\n showHeader: true,\n activeThemePreset: null,\n showNewsPanel: true,\n },\n content: {\n tone: 'engaging',\n style: 'blog',\n wordCount: 'medium',\n includeQuotes: true,\n includeFAQ: false,\n targetAudience: '',\n },\n}\n\nconst PreferencesContext = createContext<PreferencesContextType | undefined>(undefined)\n\nexport function PreferencesProvider({ children }: { children: ReactNode }) {\n const [preferences, setPreferences] = useState<Preferences | null>(defaultPreferences)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState<string | null>(null)\n\n const refreshPreferences = async () => {\n try {\n setLoading(true)\n setError(null)\n const data = await getMyPreferencesApi()\n\n if (data) {\n // Ensure logoUrl has full path\n if (data.chatbot?.logoUrl && !data.chatbot.logoUrl.startsWith('http')) {\n data.chatbot.logoUrl = `${getServerBaseUrl()}/${data.chatbot.logoUrl}`\n }\n\n // Merge API response with defaults to ensure all fields exist\n const mergedPreferences: Preferences = {\n ...defaultPreferences,\n ...data,\n chatbot: {\n ...defaultPreferences.chatbot,\n ...data.chatbot,\n },\n localization: {\n ...defaultPreferences.localization,\n ...data.localization,\n },\n appearance: {\n ...defaultPreferences.appearance,\n ...data.appearance,\n },\n content: {\n ...defaultPreferences.content,\n ...data.content,\n },\n }\n\n setPreferences(mergedPreferences)\n\n // Apply CSS variables for colors\n if (typeof document !== 'undefined') {\n document.documentElement.style.setProperty('--color-primary', mergedPreferences.chatbot?.primaryColor || '#10b981')\n document.documentElement.style.setProperty('--color-secondary', mergedPreferences.chatbot?.secondaryColor || '#064e3b')\n }\n }\n } catch (err) {\n console.error('Failed to fetch preferences:', err)\n setError(err instanceof Error ? err.message : 'Failed to load preferences')\n setPreferences(defaultPreferences)\n } finally {\n setLoading(false)\n }\n }\n\n const updatePreferences = (newPreferences: Preferences) => {\n setPreferences(newPreferences)\n\n // Apply CSS variables for colors\n if (typeof document !== 'undefined') {\n document.documentElement.style.setProperty('--color-primary', newPreferences.chatbot?.primaryColor || '#10b981')\n document.documentElement.style.setProperty('--color-secondary', newPreferences.chatbot?.secondaryColor || '#064e3b')\n }\n }\n\n useEffect(() => {\n refreshPreferences()\n }, [])\n\n return (\n <PreferencesContext.Provider\n value={{\n preferences,\n loading,\n error,\n refreshPreferences,\n updatePreferences,\n }}\n >\n {children}\n </PreferencesContext.Provider>\n )\n}\n\nexport function usePreferences() {\n const context = useContext(PreferencesContext)\n if (context === undefined) {\n throw new Error('usePreferences must be used within a PreferencesProvider')\n }\n return context\n}\n","import axios from \"axios\"\nimport { getApiBaseUrl } from \"./config\"\n\nconst api = axios.create({\n baseURL: getApiBaseUrl(),\n withCredentials: true,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n})\n\n/**\n * Request middleware\n */\napi.interceptors.request.use(\n (config) => {\n const apiKey = process.env.NEXT_PUBLIC_API_KEY\n if (apiKey) {\n config.headers[\"x-api-key\"] = apiKey\n }\n return config\n },\n (error) => Promise.reject(error)\n)\n\n/**\n * Response middleware\n */\napi.interceptors.response.use(\n (response) => response,\n (error) => {\n // Centralized error handling\n const message =\n error.response?.data?.message ||\n error.message ||\n \"Something went wrong\"\n\n return Promise.reject(message)\n }\n)\n\nexport default api\n","const DEFAULT_API_BASE_URL = \"http://localhost:8080/api\"\n\nexport function getApiBaseUrl(): string {\n return process.env.NEXT_PUBLIC_CONTENIFY_API_URL || DEFAULT_API_BASE_URL\n}\n\nexport function getServerBaseUrl(): string {\n const apiUrl = getApiBaseUrl()\n // Strip \"/api\" suffix to get server base URL (for assets like logos)\n return apiUrl.replace(/\\/api\\/?$/, \"\")\n}\n","import api from \"@/lib/api\"\n\n/**\n * Get logged-in user's chatbot preferences\n */\nexport const getMyPreferencesApi = async () => {\n const { data } = await api.get(\"/preferences/me\")\n return data.data\n}\n\n/**\n * Create or update chatbot preferences\n */\nexport const savePreferencesApi = async ({\n botName,\n logo,\n state,\n cities,\n primaryColor,\n secondaryColor,\n theme,\n language,\n showSidebar,\n showHeader,\n activeThemePreset,\n showNewsPanel,\n tone,\n style,\n wordCount,\n includeQuotes,\n includeFAQ,\n targetAudience,\n}: {\n botName?: string\n logo?: File | null\n state?: string\n cities?: string[]\n primaryColor?: string\n secondaryColor?: string\n theme?: \"light\" | \"dark\" | \"system\"\n language?: string\n showSidebar?: boolean\n showHeader?: boolean\n activeThemePreset?: string | null\n showNewsPanel?: boolean\n tone?: string\n style?: string\n wordCount?: string\n includeQuotes?: boolean\n includeFAQ?: boolean\n targetAudience?: string\n}) => {\n const formData = new FormData()\n\n if (botName) {\n formData.append(\"botName\", botName)\n }\n\n if (logo) {\n formData.append(\"logo\", logo)\n }\n\n if (state) {\n formData.append(\"state\", state)\n }\n\n if (cities) {\n formData.append(\"cities\", JSON.stringify(cities))\n }\n\n if (primaryColor) {\n formData.append(\"primaryColor\", primaryColor)\n }\n\n if (secondaryColor) {\n formData.append(\"secondaryColor\", secondaryColor)\n }\n\n if (theme) {\n formData.append(\"theme\", theme)\n }\n\n if (language) {\n formData.append(\"language\", language)\n }\n\n if (showSidebar !== undefined) {\n formData.append(\"showSidebar\", String(showSidebar))\n }\n\n if (showHeader !== undefined) {\n formData.append(\"showHeader\", String(showHeader))\n }\n\n if (activeThemePreset !== undefined) {\n formData.append(\"activeThemePreset\", activeThemePreset ?? \"\")\n }\n\n if (showNewsPanel !== undefined) {\n formData.append(\"showNewsPanel\", String(showNewsPanel))\n }\n\n if (tone) {\n formData.append(\"tone\", tone)\n }\n\n if (style) {\n formData.append(\"style\", style)\n }\n\n if (wordCount) {\n formData.append(\"wordCount\", wordCount)\n }\n\n if (includeQuotes !== undefined) {\n formData.append(\"includeQuotes\", String(includeQuotes))\n }\n\n if (includeFAQ !== undefined) {\n formData.append(\"includeFAQ\", String(includeFAQ))\n }\n\n if (targetAudience !== undefined) {\n formData.append(\"targetAudience\", targetAudience)\n }\n\n const { data } = await api.put(\"/preferences\", formData, {\n headers: {\n \"Content-Type\": \"multipart/form-data\",\n },\n })\n\n return data.data\n}\n\n/**\n * Reset chatbot preferences\n */\nexport const resetPreferencesApi = async () => {\n const { data } = await api.delete(\"/preferences/me\")\n return data\n}\n","\"use client\"\n\nimport { useState, useCallback } from \"react\"\nimport ArticleModal from \"./ArticleModal\"\nimport ChatWindow from \"./ChatWindow\"\nimport HeaderBar from \"./headerBar\"\nimport TrendingNews from \"../news/TrendingNews\"\nimport SourceSelector from \"../news/SourceSelector\"\nimport {\n rewriteNewsStreamApi,\n rewriteNewsApi,\n analyzeInputApi,\n createContentStreamApi,\n createContentApi,\n type AnalyzeInputResponse,\n type ContentOption,\n} from \"@/services/chat.service\"\nimport { useTheme } from \"@/hooks/useTheme\"\nimport { usePreferences } from \"@/contexts/PreferencesContext\"\nimport toast from \"react-hot-toast\"\nimport { Loader2 } from \"lucide-react\"\n\ntype ChatMessage = {\n id: string\n role: \"user\" | \"assistant\"\n content: string\n}\n\ninterface NewsItem {\n _id: string\n title: string\n content?: string\n sourceName?: string\n sourceUrl?: string\n category?: string\n publishedAt?: string\n}\n\nexport default function ChatBot({\n onNavigate,\n onLogout,\n}: {\n onNavigate?: (path: string) => void\n onLogout?: () => void\n} = {}) {\n const { loading, showNewsPanel } = useTheme()\n const { preferences } = usePreferences()\n const [selectedSource, setSelectedSource] = useState<string | null>(null)\n const [news, setNews] = useState<NewsItem[]>([])\n const [newsLoading, setNewsLoading] = useState(true)\n const [selectedArticle, setSelectedArticle] = useState<NewsItem | null>(null)\n const [messages, setMessages] = useState<ChatMessage[]>([])\n const [showChatMobile, setShowChatMobile] = useState(false)\n const [isStreaming, setIsStreaming] = useState(false)\n const [analyzedData, setAnalyzedData] = useState<{\n url: string\n content: string\n options: ContentOption[]\n messageId: string\n } | null>(null)\n\n const handleNewsLoaded = useCallback((loadedNews: NewsItem[]) => {\n setNews(loadedNews)\n }, [])\n\n const handleLoadingChange = useCallback((isLoading: boolean) => {\n setNewsLoading(isLoading)\n }, [])\n\nconst handleRecreate = async ({ title, content, id }: { title: string; content?: string; id?: string }) => {\n setShowChatMobile(true)\n\n const assistantId = crypto.randomUUID()\n\n // Add user message and empty assistant message\n setMessages(prev => [\n ...prev,\n {\n id: crypto.randomUUID(),\n role: \"user\",\n content: `Recreate this news:\\n${title}`,\n },\n {\n id: assistantId,\n role: \"assistant\",\n content: \"⏳ Creating article...\",\n },\n ])\n\n try {\n let accumulatedContent = \"\"\n let hasStartedStreaming = false\n\n // Get content preferences\n const contentPrefs = preferences?.content\n const lang = preferences?.localization?.language === \"hi\" ? \"Hindi\" : \"English\"\n\n // Try streaming API first\n try {\n await rewriteNewsStreamApi({\n article: content,\n language: lang,\n articleId: id,\n tone: contentPrefs?.tone,\n style: contentPrefs?.style,\n wordCount: contentPrefs?.wordCount,\n includeQuotes: contentPrefs?.includeQuotes,\n includeFAQ: contentPrefs?.includeFAQ,\n targetAudience: contentPrefs?.targetAudience,\n onChunk: (chunk: string) => {\n hasStartedStreaming = true\n // Accumulate the streamed content\n accumulatedContent += chunk\n\n // Update the message in real-time with streaming content\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: accumulatedContent }\n : m\n )\n )\n },\n onComplete: () => {\n console.log(\"Streaming completed successfully\")\n toast.success(\"Article created successfully!\")\n },\n onError: async (error) => {\n console.error(\"Streaming error:\", error)\n\n // If streaming hasn't started, try fallback to regular API\n if (!hasStartedStreaming) {\n console.log(\"Falling back to regular API...\")\n throw error // Will be caught by outer catch\n } else {\n toast.error(\"Failed to complete article generation\")\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: accumulatedContent || \"❌ Failed to create article. Please try again.\" }\n : m\n )\n )\n }\n },\n })\n } catch (streamError) {\n // Fallback to regular API if streaming fails\n console.log(\"Streaming failed, using regular API...\", streamError)\n\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: \"⏳ Generating with regular API...\" }\n : m\n )\n )\n\n const result = await rewriteNewsApi({\n article: content,\n language: lang,\n articleId: id,\n tone: contentPrefs?.tone,\n style: contentPrefs?.style,\n wordCount: contentPrefs?.wordCount,\n includeQuotes: contentPrefs?.includeQuotes,\n includeFAQ: contentPrefs?.includeFAQ,\n targetAudience: contentPrefs?.targetAudience,\n })\n\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: result.article || result }\n : m\n )\n )\n\n toast.success(\"Article created successfully!\")\n }\n } catch (err) {\n console.error(\"Complete Error:\", err)\n toast.error((err as Error)?.message || \"An error occurred while creating the article\")\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: \"❌ Failed to create article. Please try again.\" }\n : m\n )\n )\n }\n}\n\n\n\n const handleSendMessage = async (text: string) => {\n const userMsgId = crypto.randomUUID()\n const assistantId = crypto.randomUUID()\n\n // Add user message\n setMessages(prev => [\n ...prev,\n { id: userMsgId, role: \"user\", content: text },\n ])\n\n // Check if input contains a URL\n const urlRegex = /https?:\\/\\/[^\\s]+/\n const hasUrl = urlRegex.test(text)\n\n if (hasUrl) {\n // Show analyzing state\n setMessages(prev => [\n ...prev,\n { id: assistantId, role: \"assistant\", content: \"🔍 Analyzing your link...\" },\n ])\n\n try {\n const result = await analyzeInputApi(text)\n\n if (result.hasUrl && result.options?.length > 0) {\n // Store analyzed data for when user picks an action\n setAnalyzedData({\n url: result.url || \"\",\n content: result.content || \"\",\n options: result.options,\n messageId: assistantId,\n })\n\n // Show options as assistant message\n const optionsList = result.options\n .map((opt) => `• **${opt.name}**${opt.description ? ` – ${opt.description}` : \"\"}`)\n .join(\"\\n\")\n\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? {\n ...m,\n content: `I found an article (${result.wordCount || 0} words). What would you like to do?\\n\\n${optionsList}`,\n }\n : m\n )\n )\n } else {\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: \"Could not extract content from that URL. Please try a different link.\" }\n : m\n )\n )\n }\n } catch (err) {\n console.error(\"Analyze input error:\", err)\n toast.error(\"Failed to analyze the link\")\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: \"❌ Failed to analyze the link. Please try again.\" }\n : m\n )\n )\n }\n } else {\n // No URL — send as regular chat (recreate flow with the text as article)\n setMessages(prev => [\n ...prev,\n { id: assistantId, role: \"assistant\", content: \"⏳ Generating content...\" },\n ])\n setIsStreaming(true)\n\n try {\n const contentPrefs = preferences?.content\n const lang = preferences?.localization?.language === \"hi\" ? \"Hindi\" : \"English\"\n let accumulatedContent = \"\"\n\n await rewriteNewsStreamApi({\n article: text,\n language: lang,\n tone: contentPrefs?.tone,\n style: contentPrefs?.style,\n wordCount: contentPrefs?.wordCount,\n includeQuotes: contentPrefs?.includeQuotes,\n includeFAQ: contentPrefs?.includeFAQ,\n targetAudience: contentPrefs?.targetAudience,\n onChunk: (chunk: string) => {\n accumulatedContent += chunk\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId ? { ...m, content: accumulatedContent } : m\n )\n )\n },\n onComplete: () => {\n setIsStreaming(false)\n toast.success(\"Content generated!\")\n },\n onError: (error) => {\n console.error(\"Stream error:\", error)\n setIsStreaming(false)\n toast.error(\"Failed to generate content\")\n },\n })\n } catch (err) {\n console.error(\"Send message error:\", err)\n setIsStreaming(false)\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: \"❌ Failed to generate content. Please try again.\" }\n : m\n )\n )\n }\n }\n }\n\n /**\n * Handle when user selects a content action option (e.g. Recreate, Summary, etc.)\n */\n const handleSelectAction = async (actionId: string, url: string, content: string) => {\n const assistantId = crypto.randomUUID()\n\n // Clear analyzed data\n setAnalyzedData(null)\n\n const actionName = analyzedData?.options.find(o => o.id === actionId)?.name || actionId\n\n setMessages(prev => [\n ...prev,\n { id: crypto.randomUUID(), role: \"user\", content: `Action: ${actionName}` },\n { id: assistantId, role: \"assistant\", content: \"⏳ Creating content...\" },\n ])\n setIsStreaming(true)\n\n try {\n const contentPrefs = preferences?.content\n let accumulatedContent = \"\"\n\n try {\n // Try streaming first\n await createContentStreamApi({\n url,\n content,\n actionId,\n settings: {\n tone: contentPrefs?.tone,\n style: contentPrefs?.style,\n wordCount: contentPrefs?.wordCount,\n },\n onChunk: (chunk: string) => {\n accumulatedContent += chunk\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId ? { ...m, content: accumulatedContent } : m\n )\n )\n },\n onComplete: () => {\n setIsStreaming(false)\n toast.success(\"Content created!\")\n },\n onError: (error) => {\n console.error(\"Stream error:\", error)\n setIsStreaming(false)\n toast.error(\"Failed to create content\")\n },\n })\n } catch {\n // Fallback to non-streaming\n const result = await createContentApi({ url, content, actionId, settings: {\n tone: contentPrefs?.tone,\n style: contentPrefs?.style,\n wordCount: contentPrefs?.wordCount,\n }})\n\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: result.article || result.content || JSON.stringify(result) }\n : m\n )\n )\n setIsStreaming(false)\n toast.success(\"Content created!\")\n }\n } catch (err) {\n console.error(\"Create content error:\", err)\n setIsStreaming(false)\n setMessages(prev =>\n prev.map(m =>\n m.id === assistantId\n ? { ...m, content: \"❌ Failed to create content. Please try again.\" }\n : m\n )\n )\n }\n }\n\n // Show loading screen while preferences are loading\n if (loading) {\n return (\n <div className=\"w-full h-screen flex items-center justify-center bg-white\">\n <div className=\"flex flex-col items-center gap-3\">\n <Loader2 className=\"h-8 w-8 animate-spin text-gray-400\" />\n <p className=\"text-sm text-gray-500\">Loading...</p>\n </div>\n </div>\n )\n }\n\n return (\n // ✅ FULL SCREEN\n <div className=\"w-full h-screen flex flex-col bg-white\">\n \n <HeaderBar onNavigate={onNavigate} onLogout={onLogout} />\n\n {/* 🔒 Remaining screen height */}\n <div className={`flex-1 min-h-0 md:grid ${showNewsPanel ? 'md:grid-cols-12' : ''}`}>\n {/* LEFT: News List */}\n {showNewsPanel && (\n <aside className=\"relative col-span-4 bg-gray-50/60 border-r border-gray-300 h-[90vh] overflow-y-auto\">\n {/* Source Selector */}\n <div className=\"\">\n <SourceSelector\n selectedSource={selectedSource}\n onSourceChange={(value: string | null) => {\n console.log(\"Selected source:\", value);\n setSelectedSource(value)\n }}\n onNewsLoaded={handleNewsLoaded}\n onLoadingChange={handleLoadingChange}\n />\n </div>\n\n <TrendingNews\n onRecreate={handleRecreate}\n news={news}\n isLoading={newsLoading}\n />\n </aside>\n )}\n\n {/* RIGHT: Chat */}\n <section\n className={`\n ${showNewsPanel ? 'md:col-span-8' : 'w-full'} bg-white flex flex-col h-full relative\n ${showChatMobile ? \"block\" : \"hidden md:block\"}\n `}\n >\n {/* Mobile Back */}\n <div className=\"md:hidden border-b border-gray-300 p-3\">\n <button\n onClick={() => setShowChatMobile(false)}\n className=\"text-sm text-gray-600\"\n >\n ← Back to news\n </button>\n </div>\n\n {/* Chat window */}\n <div className=\"flex-1 min-h-0\">\n <ChatWindow\n messages={messages}\n onSend={handleSendMessage}\n onSelectNews={handleRecreate}\n isStreaming={isStreaming}\n analyzedData={analyzedData}\n onSelectAction={handleSelectAction}\n />\n </div>\n\n {!messages.length && (\n <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center text-center text-gray-400 text-sm px-4\">\n <div>\n <p className=\"font-medium\">AI News Assistant</p>\n <p className=\"mt-1\">\n Select a news article or type a message to begin\n </p>\n </div>\n </div>\n )}\n </section>\n </div>\n\n {selectedArticle && (\n <ArticleModal\n article={selectedArticle}\n onClose={() => setSelectedArticle(null)}\n onRecreate={handleRecreate}\n />\n )}\n </div>\n )\n}\n","\"use client\"\n\nexport default function ArticleModal({\n article,\n onClose,\n onRecreate,\n}: {\n article: { title: string; content: string; _id?: string }\n onClose: () => void\n onRecreate: (article: any) => void\n}) {\n return (\n <div className=\"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm flex items-center justify-center px-4\">\n <div className=\"relative w-full max-w-3xl bg-white rounded-xl shadow-card border border-gray-200 animate-in fade-in zoom-in\">\n {/* Header */}\n <div className=\"flex items-start justify-between px-6 py-4 border-b border-gray-300\">\n <div>\n <p className=\"text-xs text-gray-500 mb-1\">Source Article</p>\n <h2 className=\"text-lg font-semibold text-gray-900 leading-snug\">\n {article.title}\n </h2>\n </div>\n\n <button\n onClick={onClose}\n className=\"text-gray-400 hover:text-gray-700 transition\"\n aria-label=\"Close modal\"\n >\n ✕\n </button>\n </div>\n\n {/* Content */}\n <div className=\"px-6 py-5 max-h-[65vh] overflow-y-auto\">\n <div className=\"prose prose-sm max-w-none text-gray-800\">\n {article.content}\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-between px-6 py-4 border-t bg-gray-50 rounded-b-xl\">\n <span className=\"text-xs text-gray-400\">\n This content will be recreated using AI\n </span>\n\n <div className=\"flex gap-2\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 text-sm rounded-md border border-gray-300 text-gray-700 hover:bg-gray-100 transition\"\n >\n Cancel\n </button>\n <button\n onClick={() => onRecreate({\n title: article.title,\n content: article.content,\n id: article._id, // Include article ID when available\n })}\n className=\"px-4 py-2 text-sm rounded-md bg-gray-900 text-white hover:bg-black transition\"\n >\n Recreate Article\n </button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n","export function extractArticleContent(raw?: string): {\n title?: string\n article: string\n metaKeywords: string[]\n} {\n if (!raw) {\n return { article: \"\", metaKeywords: [] }\n }\n\n // Plain text (non-JSON)\n if (!raw.trim().startsWith(\"{\")) {\n return {\n article: raw,\n metaKeywords: [],\n }\n }\n\n try {\n const parsed = JSON.parse(raw)\n\n return {\n title: parsed.title || \"\",\n article: parsed.article || parsed.content || \"\",\n metaKeywords: Array.isArray(parsed.metaKeywords)\n ? parsed.metaKeywords\n : [],\n }\n } catch {\n // 🔹 Fallback for partial / broken JSON streams\n const article =\n raw\n .replace(/^[\\s\\S]*?\"article\"\\s*:\\s*\"/, \"\")\n .replace(/\"\\s*,\\s*\"metaKeywords\"[\\s\\S]*$/, \"\")\n .replace(/\"}\\s*$/, \"\") || raw\n\n return {\n article,\n metaKeywords: [],\n }\n }\n}\n","\"use client\"\n\nimport { extractArticleContent } from \"@/util/util\"\nimport { Check, Copy, Edit3, Send, SendHorizontal, Zap, X, RefreshCcw, FileText, ListChecks, Share2, BookOpen, Mail, Key } from \"lucide-react\"\nimport type { ContentOption } from \"@/services/chat.service\"\nimport { useLayoutEffect, useRef, useState, useEffect } from \"react\"\nimport EditModal from \"./EditModal\"\nimport NewsList from \"../news/NewsList\"\nimport { getTrendingNews, getNewsSources, getNewsBySource, scrapeNewsSource } from \"@/services/news.service\"\nimport Select, { SingleValue } from \"react-select\"\nimport { useTheme } from \"@/hooks/useTheme\"\nimport { usePreferences } from \"@/contexts/PreferencesContext\"\n\ninterface SourceOption {\n value: string | null\n label: string\n}\n\ntype ChatMessage = {\n id: string\n role: \"user\" | \"assistant\"\n content: string\n}\n\ntype Block =\n | { type: \"h1\"; text: string }\n | { type: \"h2\"; text: string }\n | { type: \"p\"; text: string }\n\nconst ACTION_ICONS: Record<string, typeof FileText> = {\n recreate_article: RefreshCcw,\n create_summary: ListChecks,\n create_social_posts: Share2,\n create_blog_post: BookOpen,\n create_newsletter: Mail,\n extract_key_points: Key,\n}\n\nexport default function ChatWindow({\n messages,\n onSend,\n onSelectNews,\n isStreaming = false,\n analyzedData,\n onSelectAction,\n}: {\n messages: ChatMessage[]\n onSend: (message: string) => void\n onSelectNews?: (news: { title: string; content?: string; id?: string }) => void\n isStreaming?: boolean\n analyzedData?: {\n url: string\n content: string\n options: ContentOption[]\n messageId: string\n } | null\n onSelectAction?: (actionId: string, url: string, content: string) => void\n}) {\n const { loading, showNewsPanel } = useTheme()\n const bottomRef = useRef<HTMLDivElement>(null)\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n const dropdownRef = useRef<HTMLDivElement>(null)\n const [input, setInput] = useState(\"\")\n const [copiedId, setCopiedId] = useState<string | null>(null)\n const [showNewsDropdown, setShowNewsDropdown] = useState(false)\n const [trendingNews, setTrendingNews] = useState<any[]>([])\n const [loadingNews, setLoadingNews] = useState(false)\n const [sources, setSources] = useState<any[]>([])\n const [selectedSource, setSelectedSource] = useState<string | null>(null)\n const [loadingSources, setLoadingSources] = useState(false)\n const [scraping, setScraping] = useState(false)\n const [editModal, setEditModal] = useState<{\n isOpen: boolean\n content: string\n metaKeywords: string[]\n messageId: string\n }>({ isOpen: false, content: \"\", metaKeywords: [], messageId: \"\" })\n\n const { primaryColor } = useTheme();\n const { preferences } = usePreferences();\n const preferredLanguage = preferences?.localization?.language;\n \n\n const handleCopy = async (blocks: Block[], messageId: string) => {\n try {\n const formattedText = blocksToFormattedText(blocks)\n await navigator.clipboard.writeText(formattedText)\n setCopiedId(messageId)\n setTimeout(() => setCopiedId(null), 2000)\n } catch (err) {\n console.error(\"Failed to copy:\", err)\n }\n }\n\n // Convert parsed blocks to formatted text for editing\n const blocksToFormattedText = (blocks: Block[]): string => {\n return blocks\n .map(block => {\n if (block.type === \"h1\") return `# ${block.text}`\n if (block.type === \"h2\") return `## ${block.text}`\n return block.text\n })\n .join(\"\\n\\n\")\n }\n\n const handleEdit = (blocks: Block[], metaKeywords: string[], messageId: string) => {\n const formattedContent = blocksToFormattedText(blocks)\n setEditModal({ isOpen: true, content: formattedContent, metaKeywords, messageId })\n }\n\n const handleCloseModal = () => {\n setEditModal({ isOpen: false, content: \"\", metaKeywords: [], messageId: \"\" })\n }\n\n const handleSaveDraft = (content: string, keywords: string[]) => {\n console.log(\"Saving draft:\", { content, keywords })\n // TODO: Implement save draft logic\n handleCloseModal()\n }\n\n const handlePost = (content: string, keywords: string[]) => {\n console.log(\"Posting:\", { content, keywords })\n // TODO: Implement post logic\n handleCloseModal()\n }\n\n useLayoutEffect(() => {\n bottomRef.current?.scrollIntoView({ block: \"end\" })\n }, [messages])\n\n const handleSend = () => {\n if (!input.trim()) return\n onSend(input)\n setInput(\"\")\n if (textareaRef.current) {\n textareaRef.current.style.height = \"auto\"\n }\n }\n\n // Auto-resize textarea based on content\n useEffect(() => {\n const textarea = textareaRef.current\n if (textarea) {\n textarea.style.height = \"auto\"\n textarea.style.height = `${textarea.scrollHeight}px`\n }\n }, [input])\n\n const fetchSources = async () => {\n setLoadingSources(true)\n try {\n const data = await getNewsSources()\n setSources(data || [])\n } catch (err) {\n console.error(\"Failed to fetch sources:\", err)\n } finally {\n setLoadingSources(false)\n }\n }\n\n const fetchNews = async (sourceId: string | null) => {\n setLoadingNews(true)\n try {\n let data\n if (sourceId) {\n data = await getNewsBySource(sourceId)\n } else {\n data = await getTrendingNews()\n }\n setTrendingNews(data || [])\n } catch (err) {\n console.error(\"Failed to fetch news:\", err)\n } finally {\n setLoadingNews(false)\n }\n }\n\n const handleScrape = async () => {\n if (!selectedSource) return\n setScraping(true)\n try {\n await scrapeNewsSource(selectedSource)\n await fetchNews(selectedSource)\n } catch (err) {\n console.error(\"Failed to scrape:\", err)\n } finally {\n setScraping(false)\n }\n }\n\n const handleSourceSelect = (option: SingleValue<SourceOption>) => {\n const sourceId = option?.value ?? null\n console.log(\"Selected source:\", option)\n setSelectedSource(sourceId)\n fetchNews(sourceId)\n }\n\n const handleOpenNewsDropdown = () => {\n setShowNewsDropdown(true)\n if (sources.length === 0) {\n fetchSources()\n }\n if (trendingNews.length === 0) {\n fetchNews(selectedSource)\n }\n }\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setShowNewsDropdown(false)\n }\n }\n\n if (showNewsDropdown) {\n document.addEventListener(\"mousedown\", handleClickOutside)\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside)\n }\n }, [showNewsDropdown])\n\n function formatAIContent(raw?: string): {\n blocks: Block[]\n metaKeywords: string[]\n } {\n const extracted = extractArticleContent(raw)\n\n if (!extracted || !extracted.article) {\n return { blocks: [], metaKeywords: [] }\n }\n\n const { article, metaKeywords } = extracted\n\n const normalized = article\n .replace(/^H1:\\s*/gm, \"\")\n .replace(/^H2:\\s*/gm, \"\")\n .replace(/<\\/h1>/gi, \"\\n\")\n .replace(/<\\/h2>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\")\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n\n const lines = normalized\n .split(\"\\n\")\n .map(line => line.replace(/<[^>]+>/g, \"\").trim())\n .filter(Boolean)\n\n const blocks: Block[] = []\n\n lines.forEach((line, index) => {\n // Title\n if (index === 0 && line.length < 120) {\n blocks.push({ type: \"h1\", text: line })\n return\n }\n\n // Section heading\n if (\n line.length < 90 &&\n !line.endsWith(\"।\") &&\n !line.endsWith(\".\")\n ) {\n blocks.push({ type: \"h2\", text: line })\n return\n }\n\n blocks.push({ type: \"p\", text: line })\n })\n\n return { blocks, metaKeywords }\n }\n\n return (\n <div className=\"h-full flex w-full flex-col\">\n {/* Chat Area */}\n <div className=\"flex-1 px-4 py-6\">\n <div className=\"max-w-3xl chat-scroll mx-auto space-y-6\">\n {messages.map(msg => {\n const parsed = formatAIContent(msg.content)\n\n return (\n <div key={msg.id} className=\"flex gap-3\">\n <div className=\"flex-shrink-0\">\n <div\n className=\"h-8 w-8 rounded-full flex items-center justify-center text-xs font-semibold text-white\"\n style={{\n backgroundColor: msg.role === \"assistant\" ? primaryColor : \"#1f2937\",\n }}\n >\n {msg.role === \"assistant\" ? \"AI\" : \"You\"}\n </div>\n </div>\n\n <div className=\"flex-1 text-sm space-y-3 leading-relaxed\">\n {/* Copy button for AI responses */}\n {msg.role === \"assistant\" && parsed.blocks.length > 0 && (\n <div className=\"flex justify-end -mt-1 mb-2\">\n <button\n onClick={() => handleCopy(parsed.blocks, msg.id)}\n className=\"p-1.5 rounded-md hover:bg-gray-100 transition-colors text-gray-400 hover:text-gray-600\"\n title=\"Copy to clipboard\"\n >\n {copiedId === msg.id ? (\n <Check size={16} className=\"text-emerald-600\" />\n ) : (\n <Copy size={16} />\n )}\n </button>\n </div>\n )}\n\n {parsed.blocks.map((block, idx) => {\n if (block.type === \"h1\") {\n return (\n <h1\n key={idx}\n className=\"text-sm font-semibold\"\n >\n {block.text}\n </h1>\n )\n }\n\n if (block.type === \"h2\") {\n return (\n <h2\n key={idx}\n className=\"text-base font-semibold mt-4\"\n >\n {block.text}\n </h2>\n )\n }\n\n return (\n <p key={idx} className=\"text-gray-800\">\n {block.text}\n </p>\n )\n })}\n\n {/* Meta Keywords */}\n {parsed.metaKeywords.length > 0 && (\n <div className=\"pt-4 border-t mt-6\">\n <div className=\"flex flex-wrap gap-2\">\n {parsed.metaKeywords.map((tag, i) => (\n <span\n key={i}\n className=\"text-xs px-3 py-1 rounded-full bg-gray-100 text-gray-700\"\n >\n #{tag}\n </span>\n ))}\n </div>\n </div>\n )}\n\n {/* Content action options - show when URL was analyzed */}\n {msg.role === \"assistant\" && analyzedData?.messageId === msg.id && analyzedData.options.length > 0 && (\n <div className=\"flex flex-wrap gap-2 pt-4 mt-2\">\n {analyzedData.options.map((option) => {\n const IconComponent = ACTION_ICONS[option.id] || FileText\n return (\n <button\n key={option.id}\n onClick={() => onSelectAction?.(option.id, analyzedData.url, analyzedData.content)}\n 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\"\n >\n <IconComponent size={16} />\n {option.name}\n </button>\n )\n })}\n </div>\n )}\n\n {/* Edit and Post buttons for AI responses - only show when streaming is complete */}\n {msg.role === \"assistant\" && parsed.blocks.length > 0 && !analyzedData?.messageId && (!isStreaming || msg.id !== messages[messages.length - 1]?.id) && (\n <div className=\"flex gap-3 pt-4 mt-2\">\n <button\n onClick={() => handleEdit(parsed.blocks, parsed.metaKeywords, msg.id)}\n 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\"\n >\n <Edit3 size={16} />\n Edit\n </button>\n <button\n onClick={() => handlePost(msg.content, parsed.metaKeywords)}\n className=\"flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium text-white hover:bg-emerald-700 transition-colors\"\n style={{ backgroundColor: primaryColor, color: \"#fff\" }}\n >\n <Send size={16} />\n Post\n </button>\n </div>\n )}\n </div>\n </div>\n )\n })}\n\n <div ref={bottomRef} />\n </div>\n </div>\n\n {/* Input */}\n <div className=\"shrink-0 bg-white px-4 py-3\">\n <div className=\"max-w-3xl mx-auto relative flex gap-2 items-end\">\n {/* Pulse Icon - Trending News */}\n {!showNewsPanel && <div ref={dropdownRef} className=\"absolute left-3 top-1/2 -translate-y-1/2 z-10\">\n <button\n onClick={handleOpenNewsDropdown}\n 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\"\n title=\"Select from trending news\"\n >\n <Zap size={16} />\n </button>\n\n {/* News Dropdown */}\n {showNewsDropdown && (\n <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\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-gray-100\" style={{ backgroundColor: primaryColor, color: \"#fff\" }}>\n <span className=\"text-sm font-medium text-white\">Select News</span>\n <button\n onClick={() => setShowNewsDropdown(false)}\n className=\"p-1 hover:bg-gray-200 rounded transition\"\n style={{ backgroundColor: primaryColor, color: \"#fff\" }}\n >\n <X size={14} className=\"text-white\" />\n </button>\n </div>\n\n {/* Source Selector */}\n <div className=\"px-3 py-2 border-b border-gray-100 flex items-center gap-2\">\n {/* Source Dropdown with react-select */}\n <div className=\"flex-1 min-w-[180px]\">\n <Select<SourceOption>\n options={[\n { value: null, label: \"All Sources (Trending)\" },\n ...sources\n .filter((source) => !preferredLanguage || source.language === preferredLanguage)\n .map((source) => ({\n value: source.id,\n label: source.name,\n })),\n ]}\n value={\n selectedSource\n ? { value: selectedSource, label: sources.find(s => s.id === selectedSource)?.name || selectedSource }\n : { value: null, label: \"All Sources (Trending)\" }\n }\n onChange={handleSourceSelect}\n isLoading={loadingSources}\n isDisabled={loadingSources}\n placeholder=\"Select source...\"\n classNamePrefix=\"react-select\"\n menuPlacement=\"bottom\"\n menuPosition=\"fixed\"\n menuShouldScrollIntoView={false}\n maxMenuHeight={220}\n menuPortalTarget={typeof window !== \"undefined\" ? document.body : null}\n styles={{\n container: (base) => ({\n ...base,\n width: \"100%\",\n }),\n control: (base) => ({\n ...base,\n minHeight: \"38px\",\n borderColor: \"#e5e7eb\",\n boxShadow: \"none\",\n width: \"100%\",\n }),\n menu: (base) => ({\n ...base,\n width: \"100%\",\n zIndex: 999999,\n }),\n menuPortal: (base) => ({\n ...base,\n zIndex: 999999,\n }),\n option: (base, state) => ({\n ...base,\n backgroundColor: state.isSelected\n ? primaryColor\n : state.isFocused\n ? \"#f3f4f6\"\n : \"white\",\n color: state.isSelected ? \"white\" : \"#374151\",\n cursor: \"pointer\",\n }),\n }}\n />\n </div>\n\n {/* Scrape Button */}\n {selectedSource && (\n <button\n onClick={handleScrape}\n disabled={scraping}\n 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\"\n title=\"Fetch latest news\"\n >\n <RefreshCcw size={14} className={scraping ? 'animate-spin' : ''} />\n {scraping ? 'Scraping...' : 'Scrape'}\n </button>\n )}\n\n {/* Refresh Button for trending */}\n {!selectedSource && (\n <button\n onClick={() => fetchNews(null)}\n disabled={loadingNews}\n 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\"\n >\n <RefreshCcw size={14} className={loadingNews ? 'animate-spin' : ''} />\n Refresh\n </button>\n )}\n </div>\n\n {/* News List */}\n <div className=\"overflow-y-auto max-h-[320px]\">\n {loadingNews ? (\n <div className=\"p-4 text-center text-sm text-gray-500\">\n Loading news...\n </div>\n ) : trendingNews.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-gray-500\">\n <p>No news found.</p>\n {selectedSource && (\n <p className=\"mt-1 text-xs\">Click \"Scrape\" to fetch latest news.</p>\n )}\n </div>\n ) : (\n <NewsList\n news={trendingNews.slice(0, 10)}\n onView={(item) => window.open(item.sourceUrl || item.link, \"_blank\")}\n onRecreate={(payload) => {\n setShowNewsDropdown(false)\n onSelectNews?.(payload)\n }}\n />\n )}\n </div>\n </div>\n )}\n </div>}\n\n <textarea\n ref={textareaRef}\n value={input}\n onChange={e => setInput(e.target.value)}\n onKeyDown={e => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault()\n handleSend()\n }\n }}\n rows={1}\n placeholder=\"Ask AI something…\"\n className={`flex-1 resize-none overflow-hidden border border-gray-300 ${!showNewsPanel ? '!pl-14' : '!pl-5'} !pr-[50px] input_box_textarea`}\n style={{ maxHeight: \"200px\", overflowY: input.split(\"\\n\").length > 6 ? \"auto\" : \"hidden\" }}\n />\n <button\n onClick={handleSend}\n className=\"flex h-10 w-10 absolute right-[10px] top-[5px] items-center justify-center rounded-full bg-emerald-600 text-white\"\n style={{ backgroundColor: primaryColor, color: \"#fff\" }}\n >\n <SendHorizontal size={18} />\n </button>\n </div>\n </div>\n\n {/* Edit Modal */}\n <EditModal\n isOpen={editModal.isOpen}\n initialContent={editModal.content}\n metaKeywords={editModal.metaKeywords}\n onClose={handleCloseModal}\n onSaveDraft={handleSaveDraft}\n onPost={handlePost}\n />\n </div>\n )\n}\n","\"use client\"\n\nimport { X } from \"lucide-react\"\nimport { useEffect, useState } from \"react\"\nimport RichTextEditor from \"./RichTextEditor\"\nimport { useTheme } from \"@/hooks/useTheme\"\n\ntype EditModalProps = {\n isOpen: boolean\n initialContent: string\n metaKeywords: string[]\n onClose: () => void\n onSaveDraft: (content: string, keywords: string[]) => void\n onPost: (content: string, keywords: string[]) => void\n}\n\nexport default function EditModal({\n isOpen,\n initialContent,\n metaKeywords,\n onClose,\n onSaveDraft,\n onPost,\n}: EditModalProps) {\n const { primaryColor } = useTheme();\n const [content, setContent] = useState(\"\")\n const [keywords, setKeywords] = useState<string[]>(metaKeywords)\n const [newKeyword, setNewKeyword] = useState(\"\")\n\n // Convert markdown-style content to HTML for the editor\n const markdownToHtml = (text: string): string => {\n const lines = text.split(\"\\n\").filter(line => line.trim())\n let html = \"\"\n\n lines.forEach(line => {\n const trimmed = line.trim()\n if (trimmed.startsWith(\"# \")) {\n html += `<h1>${trimmed.replace(/^#\\s+/, \"\")}</h1>`\n } else if (trimmed.startsWith(\"## \")) {\n html += `<h2>${trimmed.replace(/^##\\s+/, \"\")}</h2>`\n } else {\n html += `<p>${trimmed}</p>`\n }\n })\n\n return html\n }\n\n useEffect(() => {\n const htmlContent = markdownToHtml(initialContent)\n setContent(htmlContent)\n setKeywords(metaKeywords)\n }, [initialContent, metaKeywords])\n\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = \"hidden\"\n } else {\n document.body.style.overflow = \"\"\n }\n return () => {\n document.body.style.overflow = \"\"\n }\n }, [isOpen])\n\n const handleAddKeyword = () => {\n if (newKeyword.trim() && !keywords.includes(newKeyword.trim())) {\n setKeywords([...keywords, newKeyword.trim()])\n setNewKeyword(\"\")\n }\n }\n\n const handleRemoveKeyword = (index: number) => {\n setKeywords(keywords.filter((_, i) => i !== index))\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\") {\n e.preventDefault()\n handleAddKeyword()\n }\n }\n\n if (!isOpen) return null\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-black/50\"\n onClick={onClose}\n />\n\n {/* Modal */}\n <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\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b\">\n <h2 className=\"text-xl font-semibold text-gray-900\">Edit Article</h2>\n <button\n onClick={onClose}\n className=\"p-2 rounded-full hover:bg-gray-100 transition-colors\"\n >\n <X size={20} className=\"text-gray-500\" />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-6 space-y-6\">\n {/* Article Content - WYSIWYG Editor */}\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n Article Content\n </label>\n <RichTextEditor\n content={content}\n onChange={setContent}\n placeholder=\"Start writing your article...\"\n />\n </div>\n\n {/* Meta Keywords */}\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-2\">\n Meta Keywords\n </label>\n <div className=\"flex flex-wrap gap-2 mb-3\">\n {keywords.map((keyword, index) => (\n <span\n key={index}\n className=\"inline-flex items-center gap-1 px-3 py-1 bg-gray-100 text-gray-700 rounded-full text-sm\"\n >\n #{keyword}\n <button\n onClick={() => handleRemoveKeyword(index)}\n className=\"ml-1 text-gray-400 hover:text-gray-600\"\n >\n <X size={14} />\n </button>\n </span>\n ))}\n </div>\n <div className=\"flex gap-2\">\n <input\n type=\"text\"\n value={newKeyword}\n onChange={e => setNewKeyword(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Add a keyword...\"\n 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\"\n />\n <button\n onClick={handleAddKeyword}\n className=\"px-4 py-2 bg-gray-100 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-200 transition-colors\"\n >\n Add\n </button>\n </div>\n </div>\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 px-6 py-4 border-t bg-gray-50\">\n <button\n onClick={onClose}\n className=\"px-4 py-2 text-gray-700 text-sm font-medium hover:bg-gray-100 rounded-lg transition-colors\"\n >\n Cancel\n </button>\n <button\n onClick={() => onSaveDraft(content, keywords)}\n className=\"px-4 py-2 bg-gray-200 text-gray-800 text-sm font-medium rounded-lg hover:bg-gray-300 transition-colors\"\n >\n Save Draft\n </button>\n <button\n onClick={() => onPost(content, keywords)}\n className=\"px-4 py-2 bg-emerald-600 text-white text-sm font-medium rounded-lg hover:bg-emerald-700 transition-colors\"\n style={{ backgroundColor: primaryColor, color: \"#fff\" }}\n >\n Post\n </button>\n </div>\n </div>\n </div>\n )\n}\n","\"use client\"\n\nimport { useEditor, EditorContent } from \"@tiptap/react\"\nimport StarterKit from \"@tiptap/starter-kit\"\nimport Placeholder from \"@tiptap/extension-placeholder\"\nimport {\n Bold,\n Italic,\n List,\n ListOrdered,\n Heading1,\n Heading2,\n Undo,\n Redo,\n Pilcrow,\n} from \"lucide-react\"\nimport { useEffect } from \"react\"\n\ntype RichTextEditorProps = {\n content: string\n onChange: (content: string) => void\n placeholder?: string\n}\n\nexport default function RichTextEditor({\n content,\n onChange,\n placeholder = \"Start writing your article...\",\n}: RichTextEditorProps) {\n const editor = useEditor({\n immediatelyRender: false, // Prevents SSR hydration mismatch\n extensions: [\n StarterKit.configure({\n heading: {\n levels: [1, 2],\n },\n }),\n Placeholder.configure({\n placeholder,\n }),\n ],\n content: content,\n editorProps: {\n attributes: {\n class:\n \"prose prose-sm max-w-none focus:outline-none min-h-[350px] p-4\",\n },\n },\n onUpdate: ({ editor }) => {\n onChange(editor.getHTML())\n },\n })\n\n // Update editor content when prop changes\n useEffect(() => {\n if (editor && content !== editor.getHTML()) {\n editor.commands.setContent(content)\n }\n }, [content, editor])\n\n if (!editor) {\n return (\n <div className=\"w-full h-[400px] border border-gray-300 rounded-lg flex items-center justify-center text-gray-400\">\n Loading editor...\n </div>\n )\n }\n\n return (\n <div className=\"w-full border border-gray-300 rounded-lg overflow-hidden\">\n {/* Toolbar */}\n <div className=\"flex flex-wrap items-center gap-1 p-2 border-b border-gray-200 bg-gray-50\">\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}\n isActive={editor.isActive(\"heading\", { level: 1 })}\n title=\"Heading 1\"\n >\n <Heading1 size={18} />\n </ToolbarButton>\n\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}\n isActive={editor.isActive(\"heading\", { level: 2 })}\n title=\"Heading 2\"\n >\n <Heading2 size={18} />\n </ToolbarButton>\n\n <ToolbarButton\n onClick={() => editor.chain().focus().setParagraph().run()}\n isActive={editor.isActive(\"paragraph\")}\n title=\"Paragraph\"\n >\n <Pilcrow size={18} />\n </ToolbarButton>\n\n <div className=\"w-px h-6 bg-gray-300 mx-1\" />\n\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleBold().run()}\n isActive={editor.isActive(\"bold\")}\n title=\"Bold\"\n >\n <Bold size={18} />\n </ToolbarButton>\n\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleItalic().run()}\n isActive={editor.isActive(\"italic\")}\n title=\"Italic\"\n >\n <Italic size={18} />\n </ToolbarButton>\n\n <div className=\"w-px h-6 bg-gray-300 mx-1\" />\n\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n isActive={editor.isActive(\"bulletList\")}\n title=\"Bullet List\"\n >\n <List size={18} />\n </ToolbarButton>\n\n <ToolbarButton\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n isActive={editor.isActive(\"orderedList\")}\n title=\"Numbered List\"\n >\n <ListOrdered size={18} />\n </ToolbarButton>\n\n <div className=\"w-px h-6 bg-gray-300 mx-1\" />\n\n <ToolbarButton\n onClick={() => editor.chain().focus().undo().run()}\n disabled={!editor.can().undo()}\n title=\"Undo\"\n >\n <Undo size={18} />\n </ToolbarButton>\n\n <ToolbarButton\n onClick={() => editor.chain().focus().redo().run()}\n disabled={!editor.can().redo()}\n title=\"Redo\"\n >\n <Redo size={18} />\n </ToolbarButton>\n </div>\n\n {/* Editor */}\n <EditorContent editor={editor} className=\"min-h-[350px]\" />\n </div>\n )\n}\n\ntype ToolbarButtonProps = {\n onClick: () => void\n isActive?: boolean\n disabled?: boolean\n title: string\n children: React.ReactNode\n}\n\nfunction ToolbarButton({\n onClick,\n isActive,\n disabled,\n title,\n children,\n}: ToolbarButtonProps) {\n return (\n <button\n onClick={onClick}\n disabled={disabled}\n title={title}\n className={`p-2 rounded hover:bg-gray-200 transition-colors ${\n isActive ? \"bg-gray-200 text-emerald-600\" : \"text-gray-600\"\n } ${disabled ? \"opacity-40 cursor-not-allowed\" : \"\"}`}\n >\n {children}\n </button>\n )\n}\n","import { usePreferences } from '@/contexts/PreferencesContext'\n\nexport function useTheme() {\n const { preferences, loading } = usePreferences()\n\n return {\n loading,\n primaryColor: preferences?.chatbot?.primaryColor || '#10b981',\n secondaryColor: preferences?.chatbot?.secondaryColor || '#064e3b',\n botName: preferences?.chatbot?.name || 'AI News Assistant',\n logoUrl: preferences?.chatbot?.logoUrl,\n theme: preferences?.chatbot?.theme || 'system',\n showSidebar: preferences?.appearance?.showSidebar ?? true,\n showHeader: preferences?.appearance?.showHeader ?? true,\n activeThemePreset: preferences?.appearance?.activeThemePreset ?? null,\n showNewsPanel: preferences?.appearance?.showNewsPanel ?? true,\n }\n}\n","\"use client\"\nimport { useState } from \"react\"\nimport { Eye, RefreshCcw } from \"lucide-react\"\nimport { useTheme } from \"@/hooks/useTheme\"\n\nconst dateFormatter = new Intl.DateTimeFormat(\"en-GB\", {\n day: \"2-digit\",\n month: \"short\",\n year: \"numeric\",\n})\n\nconst timeFormatter = new Intl.DateTimeFormat(\"en-GB\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n})\n\nfunction extractLinksFromContent(html?: string) {\n if (!html) return []\n\n const parser = new DOMParser()\n const doc = parser.parseFromString(html, \"text/html\")\n\n return Array.from(doc.querySelectorAll(\"li\")).map((li) => {\n const anchor = li.querySelector(\"a\")\n const source = li.querySelector(\"font\")\n\n return {\n title: anchor?.textContent || \"\",\n url: anchor?.getAttribute(\"href\") || \"#\",\n source: source?.textContent || \"\",\n }\n })\n}\n\nexport default function NewsList({\n news,\n onView,\n onRecreate,\n}: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n news: any[]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onView: (item: any) => void\n onRecreate: (payload: { title: string; content?: string; id?: string }) => void\n}) {\n\n const { primaryColor } = useTheme();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const [primaryColorState] = useState<any>(primaryColor);\n\n const lightenColor = (hex:string, percent = 85) => {\n hex = hex.replace(\"#\", \"\");\n\n let r = parseInt(hex.substring(0, 2), 16);\n let g = parseInt(hex.substring(2, 4), 16);\n let b = parseInt(hex.substring(4, 6), 16);\n\n r = Math.round(r + (255 - r) * (percent / 100));\n g = Math.round(g + (255 - g) * (percent / 100));\n b = Math.round(b + (255 - b) * (percent / 100));\n\n return `rgb(${r}, ${g}, ${b})`;\n}\n\n\n\n\n return (\n <div className=\"p-4 space-y-3\">\n {news.flatMap((item) => {\n const publishedDate = new Date(item.publishedAt)\n const links = extractLinksFromContent(item.content)\n\n // ✅ CHILD CARDS\n if (links.length > 0) {\n return links.map((link, idx) => (\n <div\n key={`${item._id}-link-${idx}`}\n 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\"\n >\n {/* LEFT CONTENT */}\n <div className=\"min-w-0\">\n <p className=\"font-bold text-gray-900 line-clamp-2\">\n {link.title}\n </p>\n\n <div className=\"flex flex-wrap items-center gap-2 mt-2 text-xs text-gray-500\">\n <span\n className=\"inline-flex items-center rounded-full px-2 py-0.5 font-medium border\"\n style={{\n backgroundColor: lightenColor(primaryColorState, 95),\n color: primaryColor,\n borderColor: lightenColor(primaryColorState, 95),\n }}\n >\n {link.source || item.sourceName}\n </span>\n\n <span>•</span>\n <span className=\"capitalize\">{item.category}</span>\n <span>•</span>\n\n <span>\n {dateFormatter.format(publishedDate)}{\" \"}\n {timeFormatter.format(publishedDate)}\n </span>\n </div>\n </div>\n\n {/* RIGHT ACTIONS */}\n <div className=\"flex flex-col gap-2 shrink-0\">\n <button\n onClick={() => window.open(link.url, \"_blank\")}\n className=\"p-1 text-gray-400 hover:text-gray-700\"\n title=\"View\"\n >\n <Eye size={16} />\n </button>\n\n <button\n onClick={() =>\n onRecreate({\n title: link.title,\n content: link.title,\n id: item._id, // Include article ID\n })\n }\n className=\"p-1 text-gray-400 hover:text-gray-700\"\n title=\"Recreate\"\n >\n <RefreshCcw size={16} />\n </button>\n </div>\n </div>\n ))\n }\n\n // ✅ PARENT CARD\n return (\n <div\n key={item._id}\n 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\"\n >\n {/* LEFT CONTENT */}\n <div className=\"min-w-0\">\n <p className=\"font-bold text-gray-900 line-clamp-2\">\n {item.title}\n </p>\n\n <div className=\"flex flex-wrap items-center gap-2 mt-2 text-xs text-gray-500\">\n <span\n className=\"inline-flex items-center rounded-full px-2 py-0.5 font-medium border\"\n style={{\n backgroundColor: lightenColor(primaryColorState, 95),\n color: primaryColor,\n borderColor: lightenColor(primaryColorState, 95),\n }}\n >\n {item.sourceName}\n </span>\n\n <span>•</span>\n <span className=\"capitalize\">{item.category}</span>\n <span>•</span>\n\n <span>\n {dateFormatter.format(publishedDate)}{\" \"}\n {timeFormatter.format(publishedDate)}\n </span>\n </div>\n </div>\n\n {/* RIGHT ACTIONS */}\n <div className=\"flex flex-col gap-2 shrink-0\">\n <button\n onClick={() => onView(item)}\n className=\"p-1 text-gray-400 hover:text-gray-700\"\n title=\"View\"\n >\n <Eye size={16} />\n </button>\n\n <button\n onClick={() =>\n onRecreate({\n title: item.title,\n content: item.content || item.title,\n id: item._id, // Include article ID\n })\n }\n className=\"p-1 text-gray-400 hover:text-gray-700\"\n title=\"Recreate\"\n >\n <RefreshCcw size={16} />\n </button>\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n","import api from \"@/lib/api\"\n\nexport const getTrendingNews = async () => {\n const { data } = await api.get(\"/news/trending\")\n return data.data\n}\n\n/**\n * Get list of available news sources (RSS feeds)\n */\nexport const getNewsSources = async () => {\n const { data } = await api.get(\"/news/sources\")\n return data.data\n}\n\n/**\n * Scrape top 10 news from a specific source\n */\nexport const scrapeNewsSource = async (sourceId: string) => {\n const { data } = await api.post(\"/news/scrape-source\", { sourceId })\n return data.data\n}\n\n/**\n * Get previously scraped news by source\n */\nexport const getNewsBySource = async (sourceId: string) => {\n const { data } = await api.get(`/news/by-source/${sourceId}`)\n return data.data\n}\n","\"use client\"\n\nimport { useEffect, useRef, useState } from \"react\"\nimport {\n Settings,\n User,\n HelpCircle,\n LogOut,\n Palette,\n} from \"lucide-react\"\nimport toast from \"react-hot-toast\"\nimport { logoutUser } from \"@/services/auth.service\"\n\nexport default function UserMenu({\n onNavigate,\n onLogout,\n}: {\n onNavigate?: (path: string) => void\n onLogout?: () => void\n}) {\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n\n // Close on outside click\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false)\n }\n }\n document.addEventListener(\"mousedown\", handler)\n return () => document.removeEventListener(\"mousedown\", handler)\n }, [])\n\n function go(path: string) {\n setOpen(false)\n onNavigate?.(path)\n }\n\n async function logout() {\n setOpen(false)\n\n if (onLogout) {\n onLogout()\n return\n }\n\n try {\n await logoutUser()\n toast.success(\"Logged out successfully\")\n onNavigate?.(\"/login\")\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n toast.error(err || \"Logout failed\")\n }\n }\n\n return (\n <div ref={ref} className=\"relative\">\n {/* Settings Button */}\n <button\n onClick={() => setOpen(v => !v)}\n className=\"p-2 rounded-full hover:bg-gray-100 transition\"\n aria-label=\"Settings\"\n >\n <Settings size={20} className=\"text-gray-600\" />\n </button>\n\n {/* Dropdown */}\n {open && (\n <div className=\"absolute right-0 top-full mb-2 w-52 bg-white border border-gray-200 rounded-lg shadow-lg z-50\">\n <MenuItem icon={User} label=\"Account\" onClick={() => go(\"/dashboard/account\")} />\n <MenuItem icon={Settings} label=\"Preferences\" onClick={() => go(\"/dashboard/preferences\")} />\n <MenuItem icon={Palette} label=\"Appearance\" onClick={() => go(\"/dashboard/appearance\")} />\n <MenuItem icon={HelpCircle} label=\"Settings\" onClick={() => go(\"/dashboard/settings\")} />\n <MenuItem icon={HelpCircle} label=\"Help & Support\" onClick={() => go(\"/dashboard/help\")} />\n\n <div className=\"border-t border-gray-300 my-1\" />\n\n <MenuItem\n icon={LogOut}\n label=\"Logout\"\n danger\n onClick={logout}\n />\n </div>\n )}\n </div>\n )\n}\n\nfunction MenuItem({\n icon: Icon,\n label,\n onClick,\n danger = false,\n}: {\n icon: React.ComponentType<{ size: number; className?: string }>\n label: string\n onClick?: () => void\n danger?: boolean\n}) {\n return (\n <button\n onClick={onClick}\n className={`w-full flex items-center gap-2 px-4 py-2 text-sm transition ${\n danger\n ? \"text-red-600 hover:bg-red-50\"\n : \"text-gray-700 hover:bg-gray-100\"\n }`}\n >\n <Icon size={16} />\n {label}\n </button>\n )\n}\n","import api from \"@/lib/api\"\n\nexport const loginUser = async (payload: {\n email: string\n password: string\n}) => {\n const { data } = await api.post(\"/auth/login\", payload)\n return data\n}\n\nexport const signupUser = async (payload: {\n name: string\n email: string\n password: string\n}) => {\n const { data } = await api.post(\"/auth/signup\", payload)\n return data\n}\n\nexport const logoutUser = async () => {\n const { data } = await api.post(\"/auth/logout\")\n return data\n}\n","\"use client\"\n\nimport UserMenu from \"./UserMenu\"\nimport { useTheme } from \"@/hooks/useTheme\"\n\nexport default function HeaderBar({\n onNavigate,\n onLogout,\n}: {\n onNavigate?: (path: string) => void\n onLogout?: () => void\n}) {\n const { primaryColor, botName, logoUrl } = useTheme()\n\n return (\n <header className=\"sticky top-0 z-40 bg-white border-b border-gray-200\">\n <div className=\"mx-auto flex h-14 items-center justify-between px-4\">\n\n {/* Left: Logo + Brand */}\n <div className=\"flex items-center gap-3 cursor-pointer\" onClick={() => onNavigate?.('/')}>\n {logoUrl ? (\n <img src={logoUrl} alt=\"Logo\" className=\"h-8 w-8 rounded-md object-cover\" />\n ) : (\n <div\n className=\"h-8 w-8 rounded-md text-white flex items-center justify-center font-bold text-sm\"\n style={{ backgroundColor: primaryColor }}\n >\n {botName.charAt(0).toUpperCase()}\n </div>\n )}\n <span className=\"font-semibold text-gray-900 text-base\">\n {botName.toUpperCase()}\n </span>\n </div>\n\n {/* Right: User Menu */}\n <div className=\"flex items-center gap-3\">\n <UserMenu onNavigate={onNavigate} onLogout={onLogout} />\n </div>\n </div>\n </header>\n )\n}\n","\"use client\"\n\nimport { useEffect, useState, useCallback } from \"react\"\nimport NewsList from \"@/components/news/NewsList\"\nimport { getTrendingNews, getNewsBySource } from \"@/services/news.service\"\nimport toast from \"react-hot-toast\"\n\ninterface NewsItem {\n _id: string\n title: string\n content?: string\n sourceName?: string\n sourceUrl?: string\n category?: string\n publishedAt?: string\n link?: string\n}\n\ninterface TrendingNewsProps {\n onRecreate: (payload: { title: string; content?: string; id?: string }) => void\n selectedSource?: string | null\n refreshKey?: number\n news?: NewsItem[] // Optional: news passed from parent (via SourceSelector)\n isLoading?: boolean // Optional: loading state from parent\n}\n\nexport default function TrendingNews({\n onRecreate,\n selectedSource,\n refreshKey,\n news: externalNews,\n isLoading: externalLoading,\n}: TrendingNewsProps) {\n const [news, setNews] = useState<NewsItem[]>([])\n const [loading, setLoading] = useState(false)\n\n // Use external news if provided\n const displayNews = externalNews !== undefined ? externalNews : news\n const isLoading = externalLoading !== undefined ? externalLoading : loading\n\n const fetchNews = useCallback(async () => {\n // Skip fetching if news is provided externally\n if (externalNews !== undefined) {\n return\n }\n\n setLoading(true)\n try {\n let data\n if (selectedSource) {\n data = await getNewsBySource(selectedSource)\n } else {\n data = await getTrendingNews()\n }\n setNews(data || [])\n } catch {\n toast.error(\"Failed to load news\")\n } finally {\n setLoading(false)\n }\n }, [selectedSource, externalNews])\n\n useEffect(() => {\n fetchNews()\n }, [fetchNews, refreshKey])\n\n function handleView(item: NewsItem) {\n window.open(item.sourceUrl || item.link, \"_blank\")\n }\n\n if (isLoading) {\n return <div className=\"p-4 text-sm text-gray-500\">Loading news...</div>\n }\n\n if (!displayNews || displayNews.length === 0) {\n return (\n <div className=\"p-4 text-sm text-gray-500 text-center\">\n <p>No news found for this source.</p>\n <p className=\"mt-1 text-xs\">Click \"Scrape\" to fetch latest news.</p>\n </div>\n )\n }\n\n return (\n <NewsList\n news={displayNews}\n onView={handleView}\n onRecreate={onRecreate}\n />\n )\n}\n","\"use client\"\n\nimport { useEffect, useState, useCallback } from \"react\"\nimport { RefreshCcw } from \"lucide-react\"\nimport Select, { SingleValue } from \"react-select\"\nimport { getNewsSources, scrapeNewsSource, getNewsBySource, getTrendingNews } from \"@/services/news.service\"\nimport toast from \"react-hot-toast\"\nimport { useTheme } from \"@/hooks/useTheme\"\n\nexport interface NewsSource {\n _id: string\n sourceId: string\n name: string\n url?: string\n}\n\ninterface SourceOption {\n value: string\n label: string\n}\n\nconst ALL_SOURCES_VALUE = \"__all__\"\n\ninterface NewsItem {\n _id: string\n title: string\n content?: string\n sourceName?: string\n sourceUrl?: string\n category?: string\n publishedAt?: string\n}\n\ninterface SourceSelectorProps {\n selectedSource: string | null\n onSourceChange: (sourceId: string | null) => void\n onScrapeComplete?: () => void\n onNewsLoaded?: (news: NewsItem[]) => void\n onLoadingChange?: (loading: boolean) => void\n}\n\nexport default function SourceSelector({\n selectedSource,\n onSourceChange,\n onScrapeComplete,\n onNewsLoaded,\n onLoadingChange,\n}: SourceSelectorProps) {\n const [sources, setSources] = useState<NewsSource[]>([])\n const [loading, setLoading] = useState(true)\n const [scraping, setScraping] = useState(false)\n const [fetchingNews, setFetchingNews] = useState(true)\n const { primaryColor } = useTheme()\n\n // Notify parent of loading state changes\n useEffect(() => {\n onLoadingChange?.(fetchingNews)\n }, [fetchingNews, onLoadingChange])\n\n // Fetch sources on mount\n useEffect(() => {\n const fetchSources = async () => {\n try {\n const data = await getNewsSources()\n setSources(data || [])\n } catch {\n toast.error(\"Failed to load news sources\")\n } finally {\n setLoading(false)\n }\n }\n\n fetchSources()\n }, [])\n\n // Fetch news by source or trending\n const fetchNews = useCallback(async (sourceId: string | null) => {\n setFetchingNews(true)\n try {\n let news\n if (sourceId) {\n news = await getNewsBySource(sourceId)\n } else {\n news = await getTrendingNews()\n }\n onNewsLoaded?.(news || [])\n } catch (err) {\n console.error(\"Failed to fetch news:\", err)\n } finally {\n setFetchingNews(false)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Fetch news when source changes\n useEffect(() => {\n fetchNews(selectedSource)\n }, [selectedSource, fetchNews])\n\n const handleSourceSelect = (option: SingleValue<SourceOption>) => {\n const value = option?.value === ALL_SOURCES_VALUE ? null : (option?.value ?? null)\n onSourceChange(value)\n }\n\n const handleScrape = async () => {\n if (!selectedSource) {\n toast.error(\"Please select a source first\")\n return\n }\n\n setScraping(true)\n try {\n await scrapeNewsSource(selectedSource)\n toast.success(\"News scraped successfully!\")\n onScrapeComplete?.()\n\n // Refetch news after scraping\n const news = await getNewsBySource(selectedSource)\n onNewsLoaded?.(news || [])\n } catch (err) {\n toast.error((err as string) || \"Failed to scrape news\")\n } finally {\n setScraping(false)\n }\n }\n\n // Build options for react-select\n const options: SourceOption[] = [\n { value: ALL_SOURCES_VALUE, label: \"All Sources (Trending)\" },\n ...sources.map((source: any) => ({\n value: source.id,\n label: source.name,\n })),\n ]\n\n // Find current selected option\n const selectedOption = options.find((opt) =>\n selectedSource === null ? opt.value === ALL_SOURCES_VALUE : opt.value === selectedSource\n ) || options[0]\n\n return (\n <div className=\"px-3 py-2 border-b border-gray-100 flex items-center gap-2\">\n {/* Source Dropdown */}\n <div className=\"flex-1 min-w-[180px]\">\n <Select<SourceOption>\n options={options}\n value={selectedOption}\n onChange={handleSourceSelect}\n isLoading={loading}\n isDisabled={loading}\n placeholder=\"Select source...\"\n classNamePrefix=\"react-select\"\n menuPlacement=\"bottom\"\n menuPosition=\"fixed\"\n menuShouldScrollIntoView={false}\n maxMenuHeight={220}\n menuPortalTarget={typeof window !== \"undefined\" ? document.body : null}\n styles={{\n container: (base) => ({\n ...base,\n width: \"100%\",\n }),\n control: (base) => ({\n ...base,\n minHeight: \"38px\",\n borderColor: \"#e5e7eb\",\n boxShadow: \"none\",\n width: \"100%\",\n }),\n menu: (base) => ({\n ...base,\n width: \"100%\",\n zIndex: 999999,\n }),\n menuPortal: (base) => ({\n ...base,\n zIndex: 999999,\n }),\n option: (base, state) => ({\n ...base,\n backgroundColor: state.isSelected\n ? primaryColor\n : state.isFocused\n ? \"#f3f4f6\"\n : \"white\",\n color: state.isSelected ? \"white\" : \"#374151\",\n cursor: \"pointer\",\n }),\n }}\n />\n </div>\n\n {/* Scrape Button */}\n {selectedSource && (\n <button\n onClick={handleScrape}\n disabled={scraping}\n 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\"\n title=\"Fetch latest news\"\n >\n <RefreshCcw size={14} className={scraping ? 'animate-spin' : ''} />\n {scraping ? 'Scraping...' : 'Scrape'}\n </button>\n )}\n\n {/* Refresh Button for trending */}\n {!selectedSource && (\n <button\n onClick={() => fetchNews(null)}\n disabled={fetchingNews}\n 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\"\n >\n <RefreshCcw size={14} className={fetchingNews ? 'animate-spin' : ''} />\n Refresh\n </button>\n )}\n </div>\n )\n}\n","import api from \"@/lib/api\"\nimport { getApiBaseUrl } from \"@/lib/config\"\n\n/* ─── Types ─── */\n\nexport interface ContentOption {\n id: string\n name: string\n description?: string\n icon?: string\n}\n\nexport interface RecreateSettings {\n tones: string[]\n styles: string[]\n wordCounts?: string[]\n}\n\nexport interface AnalyzeInputResponse {\n hasUrl: boolean\n url?: string\n content?: string\n wordCount?: number\n options: ContentOption[]\n recreateSettings?: RecreateSettings\n}\n\nexport interface CreateContentPayload {\n url: string\n content: string\n actionId: string\n settings?: {\n tone?: string\n style?: string\n wordCount?: string\n }\n}\n\n/* ─── New API endpoints ─── */\n\n/**\n * Analyze user input for URLs and return content options\n */\nexport const analyzeInputApi = async (input: string): Promise<AnalyzeInputResponse> => {\n const { data } = await api.post(\"/chat/analyze-input\", { input })\n return data.data\n}\n\n/**\n * Create content based on selected action (non-streaming)\n */\nexport const createContentApi = async (payload: CreateContentPayload) => {\n const { data } = await api.post(\"/chat/create-content\", payload)\n return data.data\n}\n\n/**\n * Create content based on selected action (streaming)\n */\nexport const createContentStreamApi = async ({\n url,\n content,\n actionId,\n settings,\n onChunk,\n onComplete,\n onError,\n}: CreateContentPayload & {\n onChunk: (text: string) => void\n onComplete?: () => void\n onError?: (error: any) => void\n}) => {\n const API_BASE_URL = getApiBaseUrl()\n const apiKey = process.env.NEXT_PUBLIC_API_KEY\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n }\n if (apiKey) {\n headers[\"x-api-key\"] = apiKey\n }\n\n const response = await fetch(`${API_BASE_URL}/chat/create-content/stream`, {\n method: \"POST\",\n headers,\n credentials: \"include\",\n body: JSON.stringify({ url, content, actionId, settings }),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n throw new Error(`HTTP error! status: ${response.status} - ${errorText}`)\n }\n\n const reader = response.body?.getReader()\n const decoder = new TextDecoder()\n\n if (!reader) {\n throw new Error(\"No reader available\")\n }\n\n let buffer = \"\"\n let hasReceivedData = false\n\n while (true) {\n const { done, value } = await reader.read()\n\n if (done) {\n if (hasReceivedData) onComplete?.()\n break\n }\n\n const chunk = decoder.decode(value, { stream: true })\n buffer += chunk\n\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\"\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n if (trimmedLine === \"\") continue\n\n hasReceivedData = true\n\n if (trimmedLine.startsWith(\"data: \")) {\n const data = trimmedLine.slice(6).trim()\n\n if (data === \"[DONE]\") {\n onComplete?.()\n return\n }\n\n try {\n const parsed = JSON.parse(data)\n if (parsed.content) onChunk(parsed.content)\n else if (parsed.delta) onChunk(parsed.delta)\n else if (parsed.text) onChunk(parsed.text)\n else if (parsed.chunk) onChunk(parsed.chunk)\n else if (typeof parsed === \"string\") onChunk(parsed)\n } catch {\n if (data) onChunk(data)\n }\n } else if (trimmedLine) {\n onChunk(trimmedLine + \"\\n\")\n }\n }\n }\n\n if (!hasReceivedData) {\n throw new Error(\"No data received from stream\")\n }\n}\n\n/**\n * Get all available content creation options and settings\n */\nexport const getContentOptionsApi = async () => {\n const { data } = await api.get(\"/chat/content-options\")\n return data.data\n}\n\n/**\n * Streaming version of rewrite news API (like ChatGPT)\n * Calls the provided onChunk callback for each piece of streamed data\n */\nexport const rewriteNewsStreamApi = async ({\n article,\n language = \"English\",\n articleId,\n tone,\n style,\n wordCount,\n includeQuotes,\n includeFAQ,\n targetAudience,\n onChunk,\n onComplete,\n onError,\n}: {\n article: string\n language?: string\n articleId?: string\n tone?: string\n style?: string\n wordCount?: string\n includeQuotes?: boolean\n includeFAQ?: boolean\n targetAudience?: string\n onChunk: (text: string) => void\n onComplete?: () => void\n onError?: (error: any) => void\n}) => {\n const payload: Record<string, any> = {\n article,\n language,\n }\n\n // Include articleId if available\n if (articleId) {\n payload.articleId = articleId\n }\n\n // Include content generation preferences\n if (tone) payload.tone = tone\n if (style) payload.style = style\n if (wordCount) payload.wordCount = wordCount\n if (includeQuotes !== undefined) payload.includeQuotes = includeQuotes\n if (includeFAQ !== undefined) payload.includeFAQ = includeFAQ\n if (targetAudience) payload.targetAudience = targetAudience\n\n try {\n // Use the API base URL from config\n const API_BASE_URL = getApiBaseUrl()\n const apiKey = process.env.NEXT_PUBLIC_API_KEY\n\n console.log(\"🚀 Starting stream request to:\", `${API_BASE_URL}/chat/rewrite/stream`)\n console.log(\"📦 Payload:\", payload)\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n }\n\n // Add API key if available\n if (apiKey) {\n headers[\"x-api-key\"] = apiKey\n }\n\n const response = await fetch(`${API_BASE_URL}/chat/rewrite/stream`, {\n method: \"POST\",\n headers,\n credentials: \"include\", // Include cookies for authentication\n body: JSON.stringify(payload),\n })\n\n console.log(\"📡 Response status:\", response.status)\n console.log(\"📡 Response headers:\", Object.fromEntries(response.headers.entries()))\n\n if (!response.ok) {\n const errorText = await response.text()\n console.error(\"❌ API Error:\", response.status, errorText)\n throw new Error(`HTTP error! status: ${response.status} - ${errorText}`)\n }\n\n const reader = response.body?.getReader()\n const decoder = new TextDecoder()\n\n if (!reader) {\n throw new Error(\"No reader available\")\n }\n\n let buffer = \"\"\n let hasReceivedData = false\n\n while (true) {\n const { done, value } = await reader.read()\n\n if (done) {\n if (hasReceivedData) {\n onComplete?.()\n }\n break\n }\n\n // Decode the chunk\n const chunk = decoder.decode(value, { stream: true })\n buffer += chunk\n\n // Process complete lines\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\" // Keep the incomplete line in buffer\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n if (trimmedLine === \"\") continue\n\n hasReceivedData = true\n console.log(\"📨 Received line:\", trimmedLine.substring(0, 100) + (trimmedLine.length > 100 ? \"...\" : \"\"))\n\n // Handle SSE format (data: {...})\n if (trimmedLine.startsWith(\"data: \")) {\n const data = trimmedLine.slice(6).trim()\n\n if (data === \"[DONE]\") {\n console.log(\"✅ Stream completed with [DONE] signal\")\n onComplete?.()\n return\n }\n\n try {\n const parsed = JSON.parse(data)\n console.log(\"📋 Parsed JSON:\", parsed)\n\n if (parsed.content) {\n onChunk(parsed.content)\n } else if (parsed.delta) {\n onChunk(parsed.delta)\n } else if (parsed.text) {\n onChunk(parsed.text)\n } else if (parsed.chunk) {\n onChunk(parsed.chunk)\n } else if (typeof parsed === 'string') {\n onChunk(parsed)\n } else {\n console.warn(\"⚠️ Unknown JSON format:\", parsed)\n }\n } catch (e) {\n // If not JSON, treat as plain text\n console.log(\"📝 Non-JSON data, treating as plain text\")\n if (data) {\n onChunk(data)\n }\n }\n } else {\n // Plain text streaming (non-SSE format)\n console.log(\"📄 Plain text chunk\")\n if (trimmedLine) {\n onChunk(trimmedLine + \"\\n\")\n }\n }\n }\n }\n\n if (!hasReceivedData) {\n console.error(\"❌ No data received from stream\")\n throw new Error(\"No data received from stream\")\n }\n\n console.log(\"✅ Stream completed successfully\")\n } catch (error: any) {\n console.error(\"❌ Streaming error:\", error)\n console.error(\"Error details:\", {\n message: error.message,\n name: error.name,\n stack: error.stack\n })\n onError?.(error)\n throw error\n }\n}\n\n/**\n * Non-streaming version (fallback)\n */\nexport const rewriteNewsApi = async ({\n article,\n language = \"English\",\n articleId,\n tone,\n style,\n wordCount,\n includeQuotes,\n includeFAQ,\n targetAudience,\n}: {\n article: string\n language?: string\n articleId?: string\n tone?: string\n style?: string\n wordCount?: string\n includeQuotes?: boolean\n includeFAQ?: boolean\n targetAudience?: string\n}) => {\n const payload: Record<string, any> = {\n article,\n language,\n }\n\n // Include articleId if available\n if (articleId) {\n payload.articleId = articleId\n }\n\n // Include content generation preferences\n if (tone) payload.tone = tone\n if (style) payload.style = style\n if (wordCount) payload.wordCount = wordCount\n if (includeQuotes !== undefined) payload.includeQuotes = includeQuotes\n if (includeFAQ !== undefined) payload.includeFAQ = includeFAQ\n if (targetAudience) payload.targetAudience = targetAudience\n\n const { data } = await api.post(\"/chat/rewrite\", payload)\n\n return data.data;\n}\n","\"use client\"\n\nimport { PreferencesProvider } from \"../contexts/PreferencesContext\"\nimport ChatBot from \"../components/chatbot/ChatBot\"\n\nexport interface ContenifyChatBotProps {\n onNavigate?: (path: string) => void\n onLogout?: () => void\n}\n\nexport function ContenifyChatBot({ onNavigate, onLogout }: ContenifyChatBotProps) {\n return (\n <PreferencesProvider>\n <ChatBot onNavigate={onNavigate} onLogout={onLogout} />\n </PreferencesProvider>\n )\n}\n\nexport default ContenifyChatBot\n\n// Re-export types for consumers\nexport type {\n ChatbotPreferences,\n LocalizationPreferences,\n AppearancePreferences,\n ContentPreferences,\n Preferences,\n} from \"../contexts/PreferencesContext\"\n\nexport type {\n ContentOption,\n AnalyzeInputResponse,\n CreateContentPayload,\n RecreateSettings,\n} from \"../services/chat.service\"\n"],"mappings":"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","names":["useState","useCallback","jsx","X","RefreshCcw","useState","useEffect","useEffect","useState","useEffect","jsx","jsxs","editor","jsx","jsxs","useState","useEffect","useState","jsx","jsxs","useState","jsx","jsxs","RefreshCcw","useState","_a","useEffect","X","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","jsx","jsxs","useEffect","useState","toast","jsx","jsxs","useState","useEffect","useEffect","useState","useCallback","RefreshCcw","Select","toast","jsx","jsxs","useState","useEffect","toast","useCallback","Select","RefreshCcw","toast","jsx","jsxs","useState","useCallback","toast","jsx"]}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* contenify-chatbot component styles */
|
|
2
|
+
/* Consumers must have Tailwind CSS configured in their project */
|
|
3
|
+
|
|
4
|
+
:root {
|
|
5
|
+
--color-primary: #10b981;
|
|
6
|
+
--color-secondary: #064e3b;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* React Select portal fix */
|
|
10
|
+
.react-select__menu-portal {
|
|
11
|
+
pointer-events: auto !important;
|
|
12
|
+
z-index: 999999 !important;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Chat scroll container */
|
|
16
|
+
.chat-scroll {
|
|
17
|
+
overflow-y: auto !important;
|
|
18
|
+
height: 73vh;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Chat input textarea */
|
|
22
|
+
.input_box_textarea {
|
|
23
|
+
height: 50px !important;
|
|
24
|
+
border-radius: 50px;
|
|
25
|
+
padding-top: 10px !important;
|
|
26
|
+
padding-bottom: 10px;
|
|
27
|
+
padding-left: 30px;
|
|
28
|
+
padding-right: 30px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Sticky top utility */
|
|
32
|
+
.staky-top {
|
|
33
|
+
position: sticky;
|
|
34
|
+
top: 0px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* TipTap Editor Styles */
|
|
38
|
+
.ProseMirror {
|
|
39
|
+
outline: none;
|
|
40
|
+
min-height: 350px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ProseMirror h1 {
|
|
44
|
+
font-size: 1.5rem;
|
|
45
|
+
font-weight: 600;
|
|
46
|
+
color: #111827;
|
|
47
|
+
margin-bottom: 0.75rem;
|
|
48
|
+
line-height: 1.3;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ProseMirror h2 {
|
|
52
|
+
font-size: 1.125rem;
|
|
53
|
+
font-weight: 600;
|
|
54
|
+
color: #1f2937;
|
|
55
|
+
margin-top: 1.25rem;
|
|
56
|
+
margin-bottom: 0.5rem;
|
|
57
|
+
line-height: 1.4;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.ProseMirror p {
|
|
61
|
+
color: #374151;
|
|
62
|
+
margin-bottom: 0.75rem;
|
|
63
|
+
line-height: 1.7;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.ProseMirror ul,
|
|
67
|
+
.ProseMirror ol {
|
|
68
|
+
padding-left: 1.5rem;
|
|
69
|
+
margin-bottom: 0.75rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.ProseMirror ul {
|
|
73
|
+
list-style-type: disc;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.ProseMirror ol {
|
|
77
|
+
list-style-type: decimal;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.ProseMirror li {
|
|
81
|
+
margin-bottom: 0.25rem;
|
|
82
|
+
color: #374151;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ProseMirror strong {
|
|
86
|
+
font-weight: 600;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ProseMirror em {
|
|
90
|
+
font-style: italic;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* TipTap Placeholder */
|
|
94
|
+
.ProseMirror p.is-editor-empty:first-child::before {
|
|
95
|
+
content: attr(data-placeholder);
|
|
96
|
+
float: left;
|
|
97
|
+
color: #9ca3af;
|
|
98
|
+
pointer-events: none;
|
|
99
|
+
height: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Marquee animation */
|
|
103
|
+
@keyframes marquee {
|
|
104
|
+
0% {
|
|
105
|
+
transform: translateX(0%);
|
|
106
|
+
}
|
|
107
|
+
100% {
|
|
108
|
+
transform: translateX(-100%);
|
|
109
|
+
}
|
|
110
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@contenify/chatbot",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI-powered news chatbot widget for content creation",
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
},
|
|
14
|
+
"./styles.css": "./dist/styles.css"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "next dev",
|
|
21
|
+
"build": "next build",
|
|
22
|
+
"build:package": "tsup",
|
|
23
|
+
"prepublishOnly": "npm run build:package",
|
|
24
|
+
"start": "next start",
|
|
25
|
+
"lint": "eslint"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"chatbot",
|
|
32
|
+
"news",
|
|
33
|
+
"ai",
|
|
34
|
+
"content-creation",
|
|
35
|
+
"react",
|
|
36
|
+
"widget"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": ">=18.0.0",
|
|
41
|
+
"react-dom": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"react": {
|
|
45
|
+
"optional": false
|
|
46
|
+
},
|
|
47
|
+
"react-dom": {
|
|
48
|
+
"optional": false
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@tiptap/extension-placeholder": "^3.18.0",
|
|
53
|
+
"@tiptap/pm": "^3.18.0",
|
|
54
|
+
"@tiptap/react": "^3.18.0",
|
|
55
|
+
"@tiptap/starter-kit": "^3.18.0",
|
|
56
|
+
"axios": "^1.13.2",
|
|
57
|
+
"lucide-react": "^0.562.0",
|
|
58
|
+
"react-hot-toast": "^2.6.0",
|
|
59
|
+
"react-select": "^5.10.2"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@tailwindcss/postcss": "^4",
|
|
63
|
+
"@types/node": "^20",
|
|
64
|
+
"@types/react": "^19",
|
|
65
|
+
"@types/react-dom": "^19",
|
|
66
|
+
"eslint": "^9",
|
|
67
|
+
"eslint-config-next": "16.1.4",
|
|
68
|
+
"next": "^16.1.6",
|
|
69
|
+
"react": "19.2.3",
|
|
70
|
+
"react-dom": "19.2.3",
|
|
71
|
+
"tailwindcss": "^4",
|
|
72
|
+
"tsup": "^8.5.1",
|
|
73
|
+
"typescript": "^5"
|
|
74
|
+
}
|
|
75
|
+
}
|