Skip to content

Commit 8194c7e

Browse files
clean up billing page: remove fluff, fix auto-refresh flicker
- Remove "How billing works" explainer card - Remove verbose description text from auto-topup and current spend - Remove redundant billing portal button from auto-topup card - Stop 30s auto-refresh on credits (caused page flicker) - Change default auto-topup threshold from €2 to €5 Made-with: Cursor
1 parent cff4de6 commit 8194c7e

6 files changed

Lines changed: 12 additions & 75 deletions

File tree

src/app/(dashboard)/[orgSlug]/billing/page.tsx

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,68 +12,28 @@ import { AutoTopupSettings } from '@/components/billing/auto-topup-settings'
1212
import { CreditActivity } from '@/components/billing/credit-activity'
1313
import { UsageAnalytics } from '@/components/billing/usage-analytics'
1414
import { Loading } from '@/components/shared/loading'
15-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
16-
import { ArrowDownToLine, CreditCard, Sparkles } from 'lucide-react'
1715

1816
export default function BillingPage() {
1917
const { usage, isLoading: usageLoading } = useUsage()
2018
const { credits, isLoading: creditsLoading, mutate } = useCredits()
2119
const { instances, isLoading: instancesLoading } = useInstances()
2220

23-
if (usageLoading || creditsLoading || instancesLoading) return <Loading />
24-
25-
const topUpNowLabel = credits
26-
? `Top Up €${credits.auto_topup_amount_eur} Now`
27-
: 'Top Up Now'
21+
if (creditsLoading || instancesLoading) return <Loading />
2822

2923
return (
3024
<div className="space-y-6">
3125
<div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
32-
<div className="space-y-1">
33-
<h1 className="text-2xl font-bold">Billing</h1>
34-
<p className="max-w-3xl text-sm text-muted-foreground">
35-
Keep an eye on your AI credit balance, monthly usage, and the automatic refill setup that buys more credits when your balance gets low.
36-
</p>
37-
</div>
26+
<h1 className="text-2xl font-bold">Billing</h1>
3827
<div className="flex items-center gap-2">
3928
<AddCreditsButton
4029
amountEur={credits?.auto_topup_amount_eur ?? 20}
41-
label={topUpNowLabel}
30+
label="+ Add Credits"
4231
onSuccess={() => mutate()}
4332
/>
4433
<BillingPortalButton />
4534
</div>
4635
</div>
4736

48-
<Card className="border border-border/70 bg-gradient-to-br from-muted/40 via-background to-background">
49-
<CardHeader>
50-
<CardTitle>How billing works</CardTitle>
51-
</CardHeader>
52-
<CardContent className="grid gap-4 lg:grid-cols-3">
53-
<div className="rounded-xl border border-border/70 bg-background/80 p-4">
54-
<Sparkles className="h-5 w-5 text-muted-foreground" />
55-
<p className="mt-3 font-medium">AI usage spends credits</p>
56-
<p className="mt-1 text-sm text-muted-foreground">
57-
Every model request deducts from your credit balance, so the balance card tells you how much AI usage you can still run.
58-
</p>
59-
</div>
60-
<div className="rounded-xl border border-border/70 bg-background/80 p-4">
61-
<ArrowDownToLine className="h-5 w-5 text-muted-foreground" />
62-
<p className="mt-3 font-medium">Auto top-up refills low balances</p>
63-
<p className="mt-1 text-sm text-muted-foreground">
64-
Choose a refill amount and a threshold. When the balance drops below that threshold, we charge your default card and add more credits automatically.
65-
</p>
66-
</div>
67-
<div className="rounded-xl border border-border/70 bg-background/80 p-4">
68-
<CreditCard className="h-5 w-5 text-muted-foreground" />
69-
<p className="mt-3 font-medium">Cards and invoices live in Stripe</p>
70-
<p className="mt-1 text-sm text-muted-foreground">
71-
Use the billing portal to update payment methods, recover from failed top-ups, and review invoices in one place.
72-
</p>
73-
</div>
74-
</CardContent>
75-
</Card>
76-
7737
<div className="grid gap-4 xl:grid-cols-[1.15fr_0.85fr]">
7838
<CurrentSpend
7939
baseCost={usage?.base_cost ?? 0}

src/app/api/billing/credits/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export async function GET() {
2424
credit_balance_eur: orgData ? Number(orgData.credit_balance_eur) : 0,
2525
auto_topup_enabled: orgData?.auto_topup_enabled ?? true,
2626
auto_topup_amount_eur: orgData ? Number(orgData.auto_topup_amount_eur) : 20,
27-
auto_topup_threshold_eur: orgData ? Number(orgData.auto_topup_threshold_eur) : 2,
27+
auto_topup_threshold_eur: orgData ? Number(orgData.auto_topup_threshold_eur) : 5,
2828
auto_topup_failed: orgData?.auto_topup_failed ?? false,
2929
recent_transactions: transactions ?? [],
3030
})

src/components/billing/auto-topup-settings.tsx

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
} from '@/components/ui/select'
1616
import { Badge } from '@/components/ui/badge'
1717
import { AlertTriangle, Loader2 } from 'lucide-react'
18-
import { BillingPortalButton } from '@/components/billing/billing-portal-button'
1918
import { AddCreditsButton } from '@/components/billing/add-credits-button'
2019

2120
interface AutoTopupSettingsProps {
@@ -101,22 +100,12 @@ export function AutoTopupSettings({
101100
</div>
102101
</CardHeader>
103102
<CardContent className="space-y-5">
104-
<div className="rounded-xl border border-border/70 bg-muted/30 p-4">
105-
<p className="text-sm font-medium">
106-
{enabled
107-
? `Currently adds ${formatCurrency(amountEur)} when balance drops below ${formatCurrency(thresholdEur)}.`
108-
: 'Auto top-up is currently off.'}
109-
</p>
110-
<p className="mt-2 text-sm text-muted-foreground">
111-
Set the refill amount and the low-balance trigger, then enable the setup. If a payment fails, update your card and save again to retry.
112-
</p>
113-
{failed && (
114-
<div className="mt-3 flex items-center gap-2 rounded-lg bg-destructive/10 p-3 text-sm text-destructive">
115-
<AlertTriangle className="h-4 w-4 shrink-0" />
116-
Last auto top-up failed. Update your payment method, then save this setup again.
117-
</div>
118-
)}
119-
</div>
103+
{failed && (
104+
<div className="flex items-center gap-2 rounded-lg bg-destructive/10 p-3 text-sm text-destructive">
105+
<AlertTriangle className="h-4 w-4 shrink-0" />
106+
Last auto top-up failed. Update your payment method and save again to retry.
107+
</div>
108+
)}
120109

121110
<div className="grid gap-4 sm:grid-cols-2">
122111
<div className="space-y-2">
@@ -177,15 +166,6 @@ export function AutoTopupSettings({
177166
/>
178167
</div>
179168

180-
<div className="rounded-xl border border-dashed border-border px-4 py-3">
181-
<p className="text-sm font-medium">Need to update the card used for top-ups?</p>
182-
<p className="mt-1 text-sm text-muted-foreground">
183-
Open the Stripe billing portal to change your default payment method or review invoices.
184-
</p>
185-
<div className="mt-3">
186-
<BillingPortalButton />
187-
</div>
188-
</div>
189169
</CardContent>
190170
</Card>
191171
)

src/components/billing/current-spend.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ export function CurrentSpend({
6868
<p className="mt-1 text-xl font-semibold">{formatCurrency(baseCost)}</p>
6969
</div>
7070
</div>
71-
<p className="text-sm text-muted-foreground">
72-
Credits cover AI usage. Compute and plan charges are shown separately so it is clear what is prepaid vs billed monthly.
73-
</p>
7471
</CardContent>
7572
</Card>
7673
)

src/hooks/use-credits.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function useCredits() {
2525
const { data, error, isLoading, mutate } = useSWR<CreditInfo>(
2626
'/api/billing/credits',
2727
fetcher,
28-
{ refreshInterval: 30_000 },
28+
{ revalidateOnFocus: false },
2929
)
3030

3131
return {

src/lib/db/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const organizations = pgTable('organizations', {
5858
credit_balance_eur: numeric('credit_balance_eur', { precision: 10, scale: 6 }).notNull().default('0'),
5959
auto_topup_enabled: boolean('auto_topup_enabled').notNull().default(true),
6060
auto_topup_amount_eur: numeric('auto_topup_amount_eur', { precision: 10, scale: 2 }).notNull().default('20'),
61-
auto_topup_threshold_eur: numeric('auto_topup_threshold_eur', { precision: 10, scale: 2 }).notNull().default('2'),
61+
auto_topup_threshold_eur: numeric('auto_topup_threshold_eur', { precision: 10, scale: 2 }).notNull().default('5'),
6262
credit_limit_eur: numeric('credit_limit_eur', { precision: 10, scale: 2 }),
6363
auto_topup_failed: boolean('auto_topup_failed').notNull().default(false),
6464
created_at: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),

0 commit comments

Comments
 (0)