import React, { useState, useCallback } from 'react' import { useQuery } from '@tanstack/react-query' import { useNavigate, useLocation, Link } from 'react-router-dom' import { billingAPI, authAPI } from '@/services/api' import { useAuthStore } from '@/store/authStore' import { Button, Card, Input } from '@/components/ui' import { useToast } from '@/contexts/ToastContext' import { useThemeStore } from '@/store/themeStore' import { getPlanColor, formatDate } from '@/lib/utils' import { CreditCard, User, ExternalLink, AlertTriangle, Moon, Sun } from 'lucide-react' export const SettingsPage: React.FC = () => { const navigate = useNavigate() const location = useLocation() const { success: showToast, error: showError } = useToast() const { isDark, toggle: toggleTheme } = useThemeStore() const tab: 'profile' | 'billing' = location.pathname === '/settings/billing' ? 'billing' : 'profile' const handleTabChange = useCallback((newTab: 'profile' | 'billing') => { const newPath = newTab === 'billing' ? '/settings/billing' : '/settings' if (location.pathname !== newPath) { navigate(newPath, { replace: true }) } }, [navigate, location.pathname]) return (

Settings

{/* Tabs */}
{[ { id: 'profile' as const, label: 'Profile', icon: User }, { id: 'billing' as const, label: 'Billing', icon: CreditCard }, ].map(({ id, label, icon: Icon }) => ( ))}
{tab === 'profile' && } {tab === 'billing' && }
) } const ProfileSettings: React.FC<{ onToast: (msg: string) => void; onError: (msg: string) => void }> = ({ onToast, onError }) => { const { user, setAuth, token, logout } = useAuthStore() const navigate = useNavigate() const [companyName, setCompanyName] = useState(user?.company_name || '') const [currentPassword, setCurrentPassword] = useState('') const [newPassword, setNewPassword] = useState('') const [saving, setSaving] = useState(false) const [showDeleteModal, setShowDeleteModal] = useState(false) const [deleteConfirm, setDeleteConfirm] = useState('') const [deleting, setDeleting] = useState(false) const handleSave = async () => { setSaving(true) try { const payload: { company_name?: string; current_password?: string; new_password?: string } = {} if (companyName !== user?.company_name) payload.company_name = companyName if (newPassword) { payload.current_password = currentPassword payload.new_password = newPassword } if (Object.keys(payload).length === 0) { onToast('No changes to save') return } const updated = await authAPI.updateProfile(payload) setAuth(updated, token || '') setCurrentPassword('') setNewPassword('') onToast('Profile updated successfully') } catch (err) { const e = err as { response?: { data?: { detail?: string } } } onError(e.response?.data?.detail || 'Failed to update profile') } finally { setSaving(false) } } const handleDeleteAccount = async () => { if (deleteConfirm !== 'DELETE') return setDeleting(true) try { await authAPI.deleteAccount() logout() navigate('/') } catch (err) { const e = err as { response?: { data?: { detail?: string } } } onError(e.response?.data?.detail || 'Failed to delete account') setDeleting(false) } } return (

Profile Information

setCompanyName(e.target.value)} placeholder="Your company name" />
{user?.plan || 'free'} Manage plan

Change Password

setCurrentPassword(e.target.value)} placeholder="Enter current password" /> setNewPassword(e.target.value)} placeholder="Min 8 characters" hint="Leave blank to keep current password" />
{/* Danger Zone */}

Danger Zone

Permanently delete your account, all chatbots, documents, and data. This cannot be undone.

{/* Delete Account Modal */} {showDeleteModal && (

Delete Account

This will permanently delete your account and all associated data including chatbots, documents, conversations, and leads. This action cannot be undone.

Type DELETE to confirm:

setDeleteConfirm(e.target.value)} placeholder="DELETE" />
)}
) } const BillingSettings: React.FC<{ onToast: (msg: string) => void; onError: (msg: string) => void }> = ({ onError }) => { const navigate = useNavigate() const [loading, setLoading] = useState(false) const { data: subscription } = useQuery({ queryKey: ['subscription'], queryFn: billingAPI.getSubscription, }) const handlePortal = async () => { setLoading(true) try { const { url } = await billingAPI.createPortal(window.location.href) window.location.href = url } catch (err) { const e = err as { response?: { data?: { detail?: string } } } onError(e.response?.data?.detail || 'Failed to open billing portal') } finally { setLoading(false) } } const plan = subscription?.plan || 'free' const isPaid = plan !== 'free' const planFeatures: Record = { free: { published: '1', conversations: '100/month', codeExport: '❌ Agency+ only' }, starter: { published: '1', conversations: '1,500/month', codeExport: '❌ Agency+ only' }, business: { published: '3', conversations: '5,000/month', codeExport: '❌ Agency+ only' }, agency: { published: 'Unlimited', conversations: '20,000/month', codeExport: '✅ Included' }, enterprise: { published: 'Unlimited', conversations: 'Unlimited', codeExport: '✅ Included' }, } const features = planFeatures[plan] || planFeatures.free return (

Current Plan

{plan}

Status:{' '} {subscription?.status || 'active'}

{isPaid && subscription?.current_period_end && (

Renews on

{formatDate(subscription.current_period_end)}

)}
{!isPaid ? ( ) : ( )}
{/* Plan features */}

Plan Features

{[ { label: 'Chatbots published', value: features.published }, { label: 'Conversations/month', value: features.conversations }, { label: 'Code export', value: features.codeExport }, ].map(({ label, value }) => (
{label} {value}
))}
) }