import { createSignal, Show, For, onMount } from "solid-js"; import { MessageCircle, X, Send, Bot, User, Loader } from "lucide-solid"; const API = "/api/gateway"; interface ChatMessage { role: "user" | "assistant"; content: string; intent?: string; status?: string; suggestedAction?: string; } interface ChatResponse { reply: string; conversation_id: string; intent: string; confidence: number; remaining_credits?: number; remaining_daily_actions?: number; credits_charged?: number; message?: string; status?: string; suggested_action?: string; } function statusLabel(status?: string): string | null { switch (status) { case "ticket_created": return "Support ticket created"; case "kb_results": return "Help articles found"; case "usage_summary": return "AI usage summary"; default: return null; } } interface UsageStatus { remaining_credits: number; remaining_daily_actions: number; daily_action_limit: number; plan_code: string; plan_name: string; monthly_credits_total: number; monthly_credits_used: number; } export function AiChatWidget() { const [isOpen, setIsOpen] = createSignal(false); const [messages, setMessages] = createSignal([ { role: "assistant", content: "Hi! I'm Ask Ash, your Nxtgauge assistant. I can help you:\n• Search help articles & KB\n• Create support tickets\n• Explain your AI plan & usage\n• Answer questions about the platform", }, ]); const [input, setInput] = createSignal(""); const [isLoading, setIsLoading] = createSignal(false); const [conversationId, setConversationId] = createSignal(""); const [usage, setUsage] = createSignal(null); onMount(() => { fetchUsage(); }); const fetchUsage = async () => { try { const res = await fetch(`${API}/api/ai/usage/summary`); if (!res.ok) return; const data = await res.json(); const plan = data.plan_details || data.plan || {}; setUsage({ remaining_credits: plan.remaining_credits ?? data.monthly_remaining ?? 0, remaining_daily_actions: plan.remaining_daily_actions ?? data.daily_remaining ?? 0, daily_action_limit: plan.daily_action_limit ?? data.daily_limit ?? 0, plan_code: plan.plan_code ?? data.plan_code ?? "free", plan_name: plan.plan_name ?? data.plan ?? "Free", monthly_credits_total: plan.monthly_credits_total ?? data.monthly_limit ?? 0, monthly_credits_used: plan.monthly_credits_used ?? data.monthly_used ?? 0, }); } catch (err) { console.error("Failed to fetch AI usage", err); } }; const toggleChat = () => setIsOpen((v) => !v); const sendMessage = async () => { const text = input().trim(); if (!text || isLoading()) return; setIsLoading(true); const userMessage: ChatMessage = { role: "user", content: text }; setMessages((prev) => [...prev, userMessage]); setInput(""); try { let res = await fetch(`${API}/api/ai/chat/ask`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: text, conversation_id: conversationId() || undefined, }), }); if (res.status === 401 || res.status === 403 || res.status === 404) { res = await fetch(`${API}/api/ai/chat/message`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: text, conversation_id: conversationId() || undefined, }), }); } if (!res.ok) throw new Error("AI request failed"); const data: ChatResponse = await res.json(); if (data.conversation_id && !conversationId()) { setConversationId(data.conversation_id); } // Update usage state from response if available if (typeof data.remaining_credits === "number") { setUsage((prev) => prev ? { ...prev, remaining_credits: data.remaining_credits!, remaining_daily_actions: data.remaining_daily_actions ?? prev.remaining_daily_actions, } : null ); } const assistantMessage: ChatMessage = { role: "assistant", content: data.message || data.reply, intent: data.intent, status: data.status, suggestedAction: data.suggested_action, }; setMessages((prev) => [...prev, assistantMessage]); } catch (err) { setMessages((prev) => [ ...prev, { role: "assistant", content: "I'm having trouble connecting right now. Please try again or contact support@nxtgauge.com.", }, ]); } finally { setIsLoading(false); } }; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendMessage(); } }; return ( <> {/* Floating button */} {/* Chat window */}
{/* Header */}
AI Assistant { e.currentTarget.style.display = 'none'; }} />

AI Assistant

{(u) => (

{u().plan_name} · {u().remaining_credits} credits · {u().remaining_daily_actions}/{u().daily_action_limit} today

)}
{/* Quick actions */}
{[ { label: "Support Ticket", text: "I need help with " }, { label: "Search KB", text: "How do I " }, { label: "AI Plan", text: "Explain my AI plan" }, { label: "Check Balance", text: "Check my AI balance" }, ].map((action) => ( ))}
{/* Messages */}
{(msg) => (
}>

{msg.content}

{(label) => (

{label()}

)}
)}
Thinking...
{/* Input */}
setInput(e.currentTarget.value)} onKeyDown={handleKeyDown} placeholder="Ask me anything..." aria-label="Chat message input" style={{ flex: 1, height: "40px", "border-radius": "20px", border: "1px solid #E5E7EB", padding: "0 16px", "font-size": "13px", outline: "none", }} />
); }