'use client' import { useEffect, useState } from 'react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Checkbox } from '@/components/ui/checkbox' import { updateBillingConfig, updatePlanEntitlement } from '@/app/actions/admin-billing' import { toast } from 'sonner' import { useLanguage } from '@/lib/i18n' import { CreditCard, Gauge, Settings2 } from 'lucide-react' type EntitlementRow = { tier: string feature: string limitValue: number | null mode: 'limited' | 'unlimited' | 'unavailable' } type BillingAdminData = { entitlements: EntitlementRow[] billingConfig: Record usageOverview: { period: string lastSyncedAt: string | null byFeature: Array<{ feature: string; requests: number; tokens: number; users: number }> topUsers: Array<{ userId: string; email: string; name: string | null; requests: number }> } features: string[] tiers: string[] } function getEntitlement( entitlements: EntitlementRow[], tier: string, feature: string, ): EntitlementRow | undefined { return entitlements.find((e) => e.tier === tier && e.feature === feature) } export function BillingAdminClient({ initialData }: { initialData: BillingAdminData }) { const { t } = useLanguage() const [activeTier, setActiveTier] = useState(initialData.tiers[0] ?? 'BASIC') const [billingEnabled, setBillingEnabled] = useState(initialData.billingConfig.BILLING_ENABLED === 'true') const [isSavingBilling, setIsSavingBilling] = useState(false) const [savingCell, setSavingCell] = useState(null) const handleSaveBilling = async (formData: FormData) => { setIsSavingBilling(true) try { const data: Record = { BILLING_ENABLED: billingEnabled ? 'true' : 'false', STRIPE_PRICE_PRO_MONTHLY: String(formData.get('STRIPE_PRICE_PRO_MONTHLY') ?? ''), STRIPE_PRICE_PRO_ANNUAL: String(formData.get('STRIPE_PRICE_PRO_ANNUAL') ?? ''), STRIPE_PRICE_BUSINESS_MONTHLY: String(formData.get('STRIPE_PRICE_BUSINESS_MONTHLY') ?? ''), STRIPE_PRICE_BUSINESS_ANNUAL: String(formData.get('STRIPE_PRICE_BUSINESS_ANNUAL') ?? ''), } await updateBillingConfig(data) toast.success(t('admin.billing.configSaved')) } catch (e: unknown) { toast.error(e instanceof Error ? e.message : t('admin.billing.configFailed')) } finally { setIsSavingBilling(false) } } const handleEntitlementChange = async ( feature: string, mode: 'unavailable' | 'unlimited' | 'limited', limitValue?: number, ) => { const key = `${activeTier}:${feature}` setSavingCell(key) try { await updatePlanEntitlement(activeTier, feature, mode, limitValue) toast.success(t('admin.billing.limitSaved')) } catch (e: unknown) { toast.error(e instanceof Error ? e.message : t('admin.billing.limitFailed')) } finally { setSavingCell(null) } } return (

{t('admin.billing.title')}

{t('admin.billing.description')}

{t('admin.billing.stripeConfigTitle')}

{t('admin.billing.stripeConfigDescription')}

{ e.preventDefault(); handleSaveBilling(new FormData(e.currentTarget)) }} className="p-6 space-y-4">
setBillingEnabled(!!c)} />
{(['STRIPE_PRICE_PRO_MONTHLY', 'STRIPE_PRICE_PRO_ANNUAL', 'STRIPE_PRICE_BUSINESS_MONTHLY', 'STRIPE_PRICE_BUSINESS_ANNUAL'] as const).map((key) => (
))}

{t('admin.billing.secretsNote')}

{t('admin.billing.limitsTitle')}

{t('admin.billing.limitsDescription')}

{initialData.tiers.map((tier) => ( ))}
{initialData.features.map((feature) => { const row = getEntitlement(initialData.entitlements, activeTier, feature) const mode = row?.mode ?? 'unavailable' const cellKey = `${activeTier}:${feature}` return ( ) })}
{t('admin.billing.feature')} {t('admin.billing.mode')} {t('admin.billing.monthlyLimit')} {t('admin.billing.actions')}

{t('admin.billing.usageTitle')}

{t('admin.billing.usagePeriod', { period: initialData.usageOverview.period })} {initialData.usageOverview.lastSyncedAt ? ` · ${t('admin.billing.lastSync', { date: new Date(initialData.usageOverview.lastSyncedAt).toLocaleString() })}` : ` · ${t('admin.billing.notSynced')}`}

{t('admin.billing.byFeature')}

{initialData.usageOverview.byFeature.length === 0 ? (

{t('admin.billing.noUsageData')}

) : (
    {initialData.usageOverview.byFeature.map((row) => (
  • {row.feature} {row.requests} req · {row.tokens} tok
  • ))}
)}

{t('admin.billing.topUsers')}

{initialData.usageOverview.topUsers.length === 0 ? (

{t('admin.billing.noUsageData')}

) : (
    {initialData.usageOverview.topUsers.map((row) => (
  • {row.email} {row.requests} req
  • ))}
)}
) } function EntitlementRowEditor({ feature, mode: initialMode, limitValue: initialLimit, isSaving, onSave, t, }: { feature: string mode: 'unavailable' | 'unlimited' | 'limited' limitValue: number | null isSaving: boolean onSave: (feature: string, mode: 'unavailable' | 'unlimited' | 'limited', limit?: number) => Promise t: (key: string, params?: Record) => string }) { const [mode, setMode] = useState(initialMode) const [limit, setLimit] = useState(initialLimit != null ? String(initialLimit) : '50') useEffect(() => { setMode(initialMode) setLimit(initialLimit != null ? String(initialLimit) : '50') }, [initialMode, initialLimit]) return ( {feature} {mode === 'limited' ? ( setLimit(e.target.value)} className="h-9 w-24 text-xs" /> ) : ( )} ) }