suna/frontend/src/components/billing/account-billing-status.tsx

182 lines
7.4 KiB
TypeScript
Raw Normal View History

2025-04-27 07:47:06 +08:00
'use client';
import { useEffect, useState } from 'react';
import { Button } from "@/components/ui/button";
2025-04-27 10:20:49 +08:00
import { PlanComparison } from "@/components/billing/plan-comparison";
2025-04-24 12:30:08 +08:00
import { isLocalMode } from "@/lib/config";
2025-04-27 07:47:06 +08:00
import { getSubscription, createPortalSession, SubscriptionStatus } from "@/lib/api";
import { useAuth } from "@/components/AuthProvider";
import { Skeleton } from "@/components/ui/skeleton";
2025-04-12 02:57:17 +08:00
type Props = {
accountId: string;
returnUrl: string;
}
2025-04-27 07:47:06 +08:00
export default function AccountBillingStatus({ accountId, returnUrl }: Props) {
const { session, isLoading: authLoading } = useAuth();
const [subscriptionData, setSubscriptionData] = useState<SubscriptionStatus | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [isManaging, setIsManaging] = useState(false);
useEffect(() => {
async function fetchSubscription() {
if (authLoading || !session) return;
try {
const data = await getSubscription();
setSubscriptionData(data);
setError(null);
} catch (err) {
console.error('Failed to get subscription:', err);
setError(err instanceof Error ? err.message : 'Failed to load subscription data');
} finally {
setIsLoading(false);
}
}
fetchSubscription();
}, [session, authLoading]);
const handleManageSubscription = async () => {
try {
setIsManaging(true);
const { url } = await createPortalSession({ return_url: returnUrl });
window.location.href = url;
} catch (err) {
console.error('Failed to create portal session:', err);
setError(err instanceof Error ? err.message : 'Failed to create portal session');
} finally {
setIsManaging(false);
}
};
2025-04-27 01:51:25 +08:00
2025-04-24 12:30:08 +08:00
// In local development mode, show a simplified component
if (isLocalMode()) {
return (
<div className="rounded-xl border shadow-sm bg-card p-6">
<h2 className="text-xl font-semibold mb-4">Billing Status</h2>
<div className="p-4 mb-4 bg-muted/30 border border-border rounded-lg text-center">
<p className="text-sm text-muted-foreground">
Running in local development mode - billing features are disabled
</p>
<p className="text-xs text-muted-foreground mt-2">
Agent usage limits are not enforced in this environment
</p>
</div>
</div>
);
}
2025-04-12 02:57:17 +08:00
2025-04-27 07:47:06 +08:00
// Show loading state
if (isLoading || authLoading) {
return (
<div className="rounded-xl border shadow-sm bg-card p-6">
<h2 className="text-xl font-semibold mb-4">Billing Status</h2>
<div className="space-y-4">
<Skeleton className="h-20 w-full" />
<Skeleton className="h-40 w-full" />
<Skeleton className="h-10 w-full" />
</div>
</div>
);
}
// Show error state
if (error) {
2025-04-26 23:55:57 +08:00
return (
<div className="rounded-xl border shadow-sm bg-card p-6">
<h2 className="text-xl font-semibold mb-4">Billing Status</h2>
<div className="p-4 mb-4 bg-destructive/10 border border-destructive/20 rounded-lg text-center">
<p className="text-sm text-destructive">
2025-04-27 07:47:06 +08:00
Error loading billing status: {error}
2025-04-26 23:55:57 +08:00
</p>
</div>
</div>
);
}
2025-04-24 12:30:08 +08:00
const isPlan = (planId?: string) => {
2025-04-27 07:47:06 +08:00
return subscriptionData?.plan_name === planId;
2025-04-24 12:30:08 +08:00
};
2025-04-27 07:47:06 +08:00
const planName = isPlan('free')
2025-04-24 12:30:08 +08:00
? "Free"
2025-04-27 07:47:06 +08:00
: isPlan('base')
2025-04-24 12:30:08 +08:00
? "Pro"
2025-04-27 07:47:06 +08:00
: isPlan('extra')
2025-04-24 12:30:08 +08:00
? "Enterprise"
: "Unknown";
2025-04-14 08:32:08 +08:00
2025-04-12 02:57:17 +08:00
return (
2025-04-24 12:30:08 +08:00
<div className="rounded-xl border shadow-sm bg-card p-6">
<h2 className="text-xl font-semibold mb-4">Billing Status</h2>
2025-04-27 01:51:25 +08:00
{subscriptionData ? (
2025-04-24 12:30:08 +08:00
<>
<div className="mb-6">
2025-04-27 01:56:52 +08:00
<div className="rounded-lg border bg-background p-4 grid grid-cols-1 md:grid-cols-2 gap-4">
2025-04-24 12:30:08 +08:00
<div className="flex justify-between items-center">
<span className="text-sm font-medium text-foreground/90">Agent Usage This Month</span>
2025-04-27 07:47:06 +08:00
<span className="text-sm font-medium text-card-title">
{subscriptionData.current_usage?.toFixed(2) || '0'} / {subscriptionData.minutes_limit || '0'} minutes
</span>
2025-04-24 12:30:08 +08:00
</div>
</div>
</div>
{/* Plans Comparison */}
<PlanComparison
accountId={accountId}
returnUrl={returnUrl}
className="mb-6"
/>
{/* Manage Subscription Button */}
2025-04-27 07:47:06 +08:00
<Button
onClick={handleManageSubscription}
disabled={isManaging}
className="w-full bg-primary text-white hover:bg-primary/90 shadow-md hover:shadow-lg transition-all"
>
{isManaging ? "Loading..." : "Manage Subscription"}
</Button>
2025-04-24 12:30:08 +08:00
</>
2025-04-16 13:41:55 +08:00
) : (
<>
2025-04-24 12:30:08 +08:00
<div className="mb-6">
<div className="rounded-lg border bg-background p-4 gap-4">
2025-04-16 13:41:55 +08:00
<div className="flex justify-between items-center">
2025-04-24 12:30:08 +08:00
<span className="text-sm font-medium text-foreground/90">Current Plan</span>
<span className="text-sm font-medium text-card-title">Free</span>
2025-04-16 13:41:55 +08:00
</div>
2025-04-24 12:30:08 +08:00
2025-04-16 13:41:55 +08:00
<div className="flex justify-between items-center">
<span className="text-sm font-medium text-foreground/90">Agent Usage This Month</span>
2025-04-27 07:47:06 +08:00
<span className="text-sm font-medium text-card-title">
{subscriptionData?.current_usage?.toFixed(2) || '0'} / {subscriptionData?.minutes_limit || '0'} minutes
</span>
2025-04-14 08:32:08 +08:00
</div>
2025-04-12 02:57:17 +08:00
</div>
2025-04-16 13:41:55 +08:00
</div>
2025-04-14 08:32:08 +08:00
2025-04-16 13:41:55 +08:00
{/* Plans Comparison */}
<PlanComparison
accountId={accountId}
returnUrl={returnUrl}
className="mb-6"
/>
2025-04-14 08:32:08 +08:00
2025-04-16 13:41:55 +08:00
{/* Manage Subscription Button */}
2025-04-27 07:47:06 +08:00
<Button
onClick={handleManageSubscription}
disabled={isManaging}
className="w-full bg-primary text-white hover:bg-primary/90 shadow-md hover:shadow-lg transition-all"
>
{isManaging ? "Loading..." : "Manage Subscription"}
</Button>
2025-04-16 13:41:55 +08:00
</>
)}
</div>
2025-04-27 07:47:06 +08:00
);
2025-04-27 01:51:25 +08:00
}