mirror of
http://88.130.71.182:3000/BlitTech/contexta_fe.git
synced 2026-06-12 23:23:22 +00:00
Updates Apr3: new pages, components, and widespread UI/API improvements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,13 +4,16 @@ 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 } from 'lucide-react'
|
||||
import { CreditCard, User, ExternalLink, AlertTriangle, Moon, Sun } from 'lucide-react'
|
||||
|
||||
export const SettingsPage: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
const [toast, setToast] = useState('')
|
||||
const { success: showToast, error: showError } = useToast()
|
||||
const { isDark, toggle: toggleTheme } = useThemeStore()
|
||||
|
||||
const tab: 'profile' | 'billing' = location.pathname === '/settings/billing' ? 'billing' : 'profile'
|
||||
|
||||
@@ -21,14 +24,19 @@ export const SettingsPage: React.FC = () => {
|
||||
}
|
||||
}, [navigate, location.pathname])
|
||||
|
||||
const showToast = (msg: string) => {
|
||||
setToast(msg)
|
||||
setTimeout(() => setToast(''), 3500)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-3xl mx-auto">
|
||||
<h1 className="text-2xl font-bold text-gray-900 mb-6">Settings</h1>
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h1 className="text-2xl font-bold text-gray-900">Settings</h1>
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="flex items-center gap-2 px-3 py-2 rounded-lg border border-gray-200 hover:bg-gray-100 text-sm text-gray-600 transition-colors"
|
||||
aria-label="Toggle dark mode"
|
||||
>
|
||||
{isDark ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
|
||||
{isDark ? 'Light mode' : 'Dark mode'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="flex gap-1 mb-6 bg-gray-100 p-1 rounded-xl w-fit">
|
||||
@@ -51,20 +59,13 @@ export const SettingsPage: React.FC = () => {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{tab === 'profile' && <ProfileSettings onToast={showToast} />}
|
||||
{tab === 'billing' && <BillingSettings onToast={showToast} />}
|
||||
|
||||
{toast && (
|
||||
<div className="fixed bottom-4 right-4 bg-gray-900 text-white px-4 py-2 rounded-lg text-sm shadow-lg z-50 animate-fade-in-up">
|
||||
{toast}
|
||||
<button onClick={() => setToast('')} className="ml-3 opacity-60 hover:opacity-100">×</button>
|
||||
</div>
|
||||
)}
|
||||
{tab === 'profile' && <ProfileSettings onToast={showToast} onError={showError} />}
|
||||
{tab === 'billing' && <BillingSettings onToast={showToast} onError={showError} />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const ProfileSettings: React.FC<{ onToast: (msg: string) => void }> = ({ onToast }) => {
|
||||
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 || '')
|
||||
@@ -95,7 +96,7 @@ const ProfileSettings: React.FC<{ onToast: (msg: string) => void }> = ({ onToast
|
||||
onToast('Profile updated successfully')
|
||||
} catch (err) {
|
||||
const e = err as { response?: { data?: { detail?: string } } }
|
||||
onToast(e.response?.data?.detail || 'Failed to update profile')
|
||||
onError(e.response?.data?.detail || 'Failed to update profile')
|
||||
} finally {
|
||||
setSaving(false)
|
||||
}
|
||||
@@ -110,7 +111,7 @@ const ProfileSettings: React.FC<{ onToast: (msg: string) => void }> = ({ onToast
|
||||
navigate('/')
|
||||
} catch (err) {
|
||||
const e = err as { response?: { data?: { detail?: string } } }
|
||||
onToast(e.response?.data?.detail || 'Failed to delete account')
|
||||
onError(e.response?.data?.detail || 'Failed to delete account')
|
||||
setDeleting(false)
|
||||
}
|
||||
}
|
||||
@@ -211,7 +212,7 @@ const ProfileSettings: React.FC<{ onToast: (msg: string) => void }> = ({ onToast
|
||||
)
|
||||
}
|
||||
|
||||
const BillingSettings: React.FC<{ onToast: (msg: string) => void }> = ({ onToast }) => {
|
||||
const BillingSettings: React.FC<{ onToast: (msg: string) => void; onError: (msg: string) => void }> = ({ onError }) => {
|
||||
const navigate = useNavigate()
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
@@ -227,7 +228,7 @@ const BillingSettings: React.FC<{ onToast: (msg: string) => void }> = ({ onToast
|
||||
window.location.href = url
|
||||
} catch (err) {
|
||||
const e = err as { response?: { data?: { detail?: string } } }
|
||||
onToast(e.response?.data?.detail || 'Failed to open billing portal')
|
||||
onError(e.response?.data?.detail || 'Failed to open billing portal')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user