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
{isDark ? : }
{isDark ? 'Light mode' : 'Dark mode'}
{/* Tabs */}
{[
{ id: 'profile' as const, label: 'Profile', icon: User },
{ id: 'billing' as const, label: 'Billing', icon: CreditCard },
].map(({ id, label, icon: Icon }) => (
handleTabChange(id)}
className={`flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
tab === id
? 'bg-white shadow-sm text-gray-900'
: 'text-gray-500 hover:text-gray-700'
}`}
>
{label}
))}
{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 (
)
}
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 ? (
navigate('/pricing')} className="flex-1">
Upgrade Plan
) : (
Manage Billing
)}
{/* 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}
))}
)
}