import { useState, useEffect, useCallback } from 'react' import { Plus, Trash2, ToggleLeft } from 'lucide-react' import { DataTable, PageHeader, StatusBadge, ActionMenu, EmptyState } from '@/components/admin' import type { Column } from '@/components/admin' import { Modal } from '@/components/common/Modal' import { adminApi } from '@/api/admin' import { toast } from '@/lib/toast' import { cn } from '@/lib/utils' import type { FeatureFlagResponse, FeatureFlagCreate, AccountFeatureOverrideResponse, AccountFeatureOverrideCreate } from '@/types/admin' const PLANS = ['free', 'pro', 'team'] export function FeatureFlagsPage() { const [flags, setFlags] = useState([]) const [overrides, setOverrides] = useState([]) const [loading, setLoading] = useState(true) const [createOpen, setCreateOpen] = useState(false) const [createForm, setCreateForm] = useState({ flag_key: '', display_name: '', description: '' }) const [overrideOpen, setOverrideOpen] = useState(false) const [overrideForm, setOverrideForm] = useState({ account_display_code: '', flag_id: '', enabled: true, note: '' }) const fetchData = useCallback(async () => { setLoading(true) try { const [flagData, overrideData] = await Promise.all([ adminApi.listFeatureFlags(), adminApi.listFeatureFlagOverrides(), ]) setFlags(flagData) setOverrides(overrideData) } catch { toast.error('Failed to load feature flags') } finally { setLoading(false) } }, []) useEffect(() => { fetchData() }, [fetchData]) const handleCreate = async () => { try { await adminApi.createFeatureFlag(createForm) toast.success('Feature flag created') setCreateOpen(false) setCreateForm({ flag_key: '', display_name: '', description: '' }) fetchData() } catch { toast.error('Failed to create feature flag') } } const handleTogglePlan = async (flagId: string, plan: string, currentEnabled: boolean) => { try { await adminApi.updatePlanDefault({ plan, flag_id: flagId, enabled: !currentEnabled }) toast.success('Plan default updated') fetchData() } catch { toast.error('Failed to update plan default') } } const handleDeleteFlag = async (id: string) => { try { await adminApi.deleteFeatureFlag(id) toast.success('Feature flag deleted') fetchData() } catch { toast.error('Failed to delete feature flag') } } const handleCreateOverride = async () => { try { await adminApi.createFeatureFlagOverride(overrideForm) toast.success('Override created') setOverrideOpen(false) fetchData() } catch { toast.error('Failed to create override') } } const handleDeleteOverride = async (id: string) => { try { await adminApi.deleteFeatureFlagOverride(id) toast.success('Override deleted') fetchData() } catch { toast.error('Failed to delete override') } } const flagColumns: Column[] = [ { key: 'name', header: 'Name', render: (f) => (
{f.display_name}
{f.flag_key}
)}, { key: 'description', header: 'Description', render: (f) => {f.description || '-'} }, ...PLANS.map(plan => ({ key: plan, header: plan.charAt(0).toUpperCase() + plan.slice(1), render: (f: FeatureFlagResponse) => { const entry = f.plan_defaults.find(d => d.plan === plan) const enabled = entry?.enabled ?? false return ( ) }, })), { key: 'actions', header: '', className: 'w-12', render: (f) => ( , onClick: () => handleDeleteFlag(f.id), destructive: true }, ]} /> ), }, ] const overrideColumns: Column[] = [ { key: 'account', header: 'Account', render: (o) => {o.account_display_code || o.account_id.slice(0, 8)} }, { key: 'flag', header: 'Flag', render: (o) => {o.flag_display_name || o.flag_key || o.flag_id.slice(0, 8)} }, { key: 'enabled', header: 'Enabled', render: (o) => {o.enabled ? 'Yes' : 'No'} }, { key: 'note', header: 'Note', render: (o) => {o.note || '-'} }, { key: 'actions', header: '', className: 'w-12', render: (o) => ( , onClick: () => handleDeleteOverride(o.id), destructive: true }, ]} /> ), }, ] const inputCn = cn('w-full rounded-md border border-white/10 bg-black/50 px-3 py-2 text-sm text-white', 'placeholder:text-white/40 focus:outline-none focus:border-white/30 focus:ring-2 focus:ring-white/20') return (
setCreateOpen(true)} className={cn('flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium', 'bg-white text-black hover:bg-white/90')}> Create Flag } />

Feature Matrix

f.id} isLoading={loading} emptyState={} title="No feature flags" description="Create feature flags to control availability per plan." />} />

Account Overrides

o.id} isLoading={loading} emptyState={} title="No overrides" description="Account-specific feature overrides will appear here." />} />
{/* Create Flag Modal */} setCreateOpen(false)} title="Create Feature Flag" size="sm" footer={
} >
setCreateForm({ ...createForm, flag_key: e.target.value })} placeholder="e.g. custom_branding" className={inputCn} />
setCreateForm({ ...createForm, display_name: e.target.value })} placeholder="e.g. Custom Branding" className={inputCn} />
setCreateForm({ ...createForm, description: e.target.value || null })} placeholder="Optional description" className={inputCn} />
{/* Create Override Modal */} setOverrideOpen(false)} title="Add Account Override" size="sm" footer={
} >
setOverrideForm({ ...overrideForm, account_display_code: e.target.value })} placeholder="e.g. ABC-1234" className={inputCn} />
setOverrideForm({ ...overrideForm, enabled: e.target.checked })} className="h-4 w-4 rounded border-white/10" />
setOverrideForm({ ...overrideForm, note: e.target.value || null })} placeholder="Reason" className={inputCn} />
) } export default FeatureFlagsPage