2025-04-12 02:57:17 +08:00
|
|
|
import { createClient } from "@/lib/supabase/server";
|
|
|
|
import { SubmitButton } from "../ui/submit-button";
|
2025-04-14 08:32:08 +08:00
|
|
|
import { manageSubscription } from "@/lib/actions/billing";
|
2025-04-24 12:30:08 +08:00
|
|
|
import { PlanComparison, SUBSCRIPTION_PLANS } from "../billing/plan-comparison";
|
|
|
|
import { isLocalMode } from "@/lib/config";
|
2025-04-12 02:57:17 +08:00
|
|
|
|
|
|
|
type Props = {
|
|
|
|
accountId: string;
|
|
|
|
returnUrl: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default async function AccountBillingStatus({ accountId, returnUrl }: Props) {
|
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-24 12:30:08 +08:00
|
|
|
const supabaseClient = await createClient();
|
|
|
|
|
2025-04-26 23:55:57 +08:00
|
|
|
// Get billing status using the new billing functions
|
|
|
|
const { data: billingStatus, error: billingError } = await supabaseClient.functions.invoke('billing-functions', {
|
|
|
|
body: {
|
|
|
|
action: "get_billing_status",
|
|
|
|
args: {
|
|
|
|
account_id: accountId
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (billingError) {
|
|
|
|
console.error("Error fetching billing status:", billingError);
|
|
|
|
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">
|
|
|
|
Error loading billing information. Please try again later.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2025-04-24 12:30:08 +08:00
|
|
|
// Get agent runs for this account
|
|
|
|
const { data: threads } = await supabaseClient
|
2025-04-23 00:15:29 +08:00
|
|
|
.from('threads')
|
|
|
|
.select('thread_id')
|
|
|
|
.eq('account_id', accountId);
|
2025-04-24 12:30:08 +08:00
|
|
|
|
|
|
|
const threadIds = threads?.map(t => t.thread_id) || [];
|
|
|
|
|
|
|
|
// Get current month usage
|
|
|
|
const now = new Date();
|
|
|
|
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
|
|
const isoStartOfMonth = startOfMonth.toISOString();
|
|
|
|
|
|
|
|
let totalAgentTime = 0;
|
|
|
|
let usageDisplay = "No usage this month";
|
|
|
|
|
|
|
|
if (threadIds.length > 0) {
|
|
|
|
const { data: agentRuns } = await supabaseClient
|
|
|
|
.from('agent_runs')
|
|
|
|
.select('started_at, completed_at')
|
|
|
|
.in('thread_id', threadIds)
|
|
|
|
.gte('started_at', isoStartOfMonth);
|
|
|
|
|
|
|
|
if (agentRuns && agentRuns.length > 0) {
|
|
|
|
const nowTimestamp = now.getTime();
|
|
|
|
|
|
|
|
totalAgentTime = agentRuns.reduce((total, run) => {
|
|
|
|
const startTime = new Date(run.started_at).getTime();
|
|
|
|
const endTime = run.completed_at
|
|
|
|
? new Date(run.completed_at).getTime()
|
|
|
|
: nowTimestamp;
|
|
|
|
|
|
|
|
return total + (endTime - startTime) / 1000; // In seconds
|
|
|
|
}, 0);
|
|
|
|
|
|
|
|
// Convert to minutes
|
|
|
|
const totalMinutes = Math.round(totalAgentTime / 60);
|
|
|
|
usageDisplay = `${totalMinutes} minutes`;
|
|
|
|
}
|
2025-04-14 08:32:08 +08:00
|
|
|
}
|
2025-04-24 12:30:08 +08:00
|
|
|
|
|
|
|
const isPlan = (planId?: string) => {
|
2025-04-26 23:55:57 +08:00
|
|
|
return billingStatus?.subscription_id === planId;
|
2025-04-24 12:30:08 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const planName = isPlan(SUBSCRIPTION_PLANS.FREE)
|
|
|
|
? "Free"
|
|
|
|
: isPlan(SUBSCRIPTION_PLANS.PRO)
|
|
|
|
? "Pro"
|
|
|
|
: isPlan(SUBSCRIPTION_PLANS.ENTERPRISE)
|
|
|
|
? "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-26 23:55:57 +08:00
|
|
|
{billingStatus?.subscription_active ? (
|
2025-04-24 12:30:08 +08:00
|
|
|
<>
|
|
|
|
<div className="mb-6">
|
|
|
|
<div className="rounded-lg border bg-background p-4 grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
<div>
|
|
|
|
<div className="flex justify-between items-center">
|
|
|
|
<span className="text-sm font-medium text-foreground/90">Current Plan</span>
|
|
|
|
<span className="text-sm font-medium text-card-title">{planName}</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="flex justify-between items-center">
|
|
|
|
<span className="text-sm font-medium text-foreground/90">Agent Usage This Month</span>
|
|
|
|
<span className="text-sm font-medium text-card-title">{usageDisplay}</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{/* Plans Comparison */}
|
|
|
|
<PlanComparison
|
|
|
|
accountId={accountId}
|
|
|
|
returnUrl={returnUrl}
|
|
|
|
className="mb-6"
|
|
|
|
/>
|
|
|
|
|
|
|
|
{/* Manage Subscription Button */}
|
|
|
|
<form>
|
|
|
|
<input type="hidden" name="accountId" value={accountId} />
|
|
|
|
<input type="hidden" name="returnUrl" value={returnUrl} />
|
|
|
|
<SubmitButton
|
|
|
|
pendingText="Loading..."
|
|
|
|
formAction={manageSubscription}
|
|
|
|
className="w-full bg-primary text-white hover:bg-primary/90 shadow-md hover:shadow-lg transition-all"
|
|
|
|
>
|
|
|
|
Manage Subscription
|
|
|
|
</SubmitButton>
|
|
|
|
</form>
|
|
|
|
</>
|
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>
|
|
|
|
<span className="text-sm font-medium text-card-title">{usageDisplay}</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 */}
|
|
|
|
<form>
|
|
|
|
<input type="hidden" name="accountId" value={accountId} />
|
|
|
|
<input type="hidden" name="returnUrl" value={returnUrl} />
|
|
|
|
<SubmitButton
|
|
|
|
pendingText="Loading..."
|
|
|
|
formAction={manageSubscription}
|
|
|
|
className="w-full bg-primary text-white hover:bg-primary/90 shadow-md hover:shadow-lg transition-all"
|
|
|
|
>
|
|
|
|
Manage Subscription
|
|
|
|
</SubmitButton>
|
|
|
|
</form>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</div>
|
2025-04-12 02:57:17 +08:00
|
|
|
)
|
|
|
|
}
|