import React, { useState, useEffect, useCallback } from 'react' import { useParams, useNavigate, Link } from 'react-router-dom' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { chatbotsAPI, documentsAPI, modelsAPI } from '@/services/api' import { useAuthStore } from '@/store/authStore' import { Button, Input, Textarea, Select, Card, Badge, StatusDot, Spinner } from '@/components/ui' import { CATEGORIES, INDUSTRIES, LANGUAGES, formatBytes, getFileIcon } from '@/lib/utils' import { ChatInterface } from '@/components/ChatInterface' import { useDropzone } from 'react-dropzone' import type { ChatbotFormData, AvailableModel } from '@/types' import { ArrowLeft, Save, Eye, Upload, Trash2, FileText, Bot, Sliders, Globe, Code, AlertCircle, CheckCircle, ChevronDown, ChevronRight, Settings2, ImagePlus, X } from 'lucide-react' const DEFAULT_FORM: ChatbotFormData = { name: '', description: '', system_prompt: '', model: 'accounts/fireworks/models/kimi-k2-instruct-0905', temperature: 0.7, max_tokens: 1000, primary_color: '#6366f1', welcome_message: 'Hello! How can I help you today?', logo_url: '', category: '', industry: '', languages: ['en'], } type Tab = 'settings' | 'documents' | 'preview' export const ChatbotBuilderPage: React.FC = () => { const { id } = useParams<{ id: string }>() const isNew = !id || id === 'new' const navigate = useNavigate() const queryClient = useQueryClient() const { user } = useAuthStore() const [tab, setTab] = useState('settings') const [form, setForm] = useState(DEFAULT_FORM) const [toast, setToast] = useState<{ msg: string; type: 'success' | 'error' } | null>(null) const [chatbotId, setChatbotId] = useState(isNew ? null : id || null) // Load existing chatbot const { data: existingChatbot, isLoading: loadingChatbot } = useQuery({ queryKey: ['chatbot', id], queryFn: () => chatbotsAPI.get(id!), enabled: !isNew, }) useEffect(() => { if (existingChatbot) { setForm({ name: existingChatbot.name, description: existingChatbot.description || '', system_prompt: existingChatbot.system_prompt || '', model: existingChatbot.model, temperature: existingChatbot.temperature, max_tokens: existingChatbot.max_tokens, primary_color: existingChatbot.primary_color, welcome_message: existingChatbot.welcome_message, logo_url: existingChatbot.logo_url || '', category: existingChatbot.category || '', industry: existingChatbot.industry || '', languages: existingChatbot.languages, }) setChatbotId(existingChatbot.id) } }, [existingChatbot]) const createMutation = useMutation({ mutationFn: chatbotsAPI.create, onSuccess: (data) => { setChatbotId(data.id) queryClient.invalidateQueries({ queryKey: ['chatbots'] }) navigate(`/chatbots/${data.id}/edit`, { replace: true }) showToast('Chatbot created!', 'success') }, onError: (err: any) => showToast(err.response?.data?.detail || 'Failed to create', 'error'), }) const updateMutation = useMutation({ mutationFn: (data: Partial) => chatbotsAPI.update(chatbotId!, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['chatbot', chatbotId] }) queryClient.invalidateQueries({ queryKey: ['chatbots'] }) showToast('Settings saved!', 'success') }, onError: (err: any) => showToast(err.response?.data?.detail || 'Save failed', 'error'), }) const handleSave = () => { if (!form.name.trim()) { showToast('Chatbot name is required', 'error'); return } if (isNew || !chatbotId) { createMutation.mutate(form) } else { updateMutation.mutate(form) } } const showToast = (msg: string, type: 'success' | 'error') => { setToast({ msg, type }) setTimeout(() => setToast(null), 3000) } if (loadingChatbot) { return
} return (
{/* Top bar */}

{isNew ? 'Create Chatbot' : `Edit: ${form.name || 'Untitled'}`}

{/* Tabs */}
{([ { key: 'settings' as Tab, label: 'Settings', icon: Sliders }, { key: 'documents' as Tab, label: 'Documents', icon: FileText }, { key: 'preview' as Tab, label: 'Preview', icon: Eye }, ]).map(t => ( ))}
{/* Content */}
{tab === 'settings' && ( )} {tab === 'documents' && chatbotId && } {tab === 'documents' && !chatbotId && (

Save your chatbot first to upload documents.

)} {tab === 'preview' && chatbotId && (
)} {tab === 'preview' && !chatbotId && (

Save your chatbot first to preview it.

)}
{/* Toast */} {toast && (
{toast.type === 'success' ? : } {toast.msg}
)}
) } // ═══════════════════════════════════════════════════════════════════════════════ // SETTINGS TAB // ═══════════════════════════════════════════════════════════════════════════════ interface SettingsTabProps { form: ChatbotFormData setForm: React.Dispatch> userPlan: string } const SettingsTab: React.FC = ({ form, setForm, userPlan }) => { const [advancedOpen, setAdvancedOpen] = useState(false) const set = (field: keyof ChatbotFormData) => (value: any) => { setForm(prev => ({ ...prev, [field]: value })) } // ── IMPROVEMENT #3: Load models dynamically from backend ────────────────── const { data: modelsData, isLoading: modelsLoading } = useQuery({ queryKey: ['available-models'], queryFn: modelsAPI.available, staleTime: 5 * 60 * 1000, // cache for 5 minutes }) const availableModels = modelsData?.models || [] const hasPremiumAccess = modelsData?.has_premium_access || false const upgradeLabel = modelsData?.upgrade_label || null return (
{/* Basic Info */}

Basic Info

set('name')(e.target.value)} placeholder="e.g. Customer Support Bot" />