Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Button } from "@superset/ui/button";
import { Link } from "@tanstack/react-router";
import { HiArrowRight } from "react-icons/hi2";
import {
isItemVisible,
SETTING_ITEM_ID,
type SettingItemId,
} from "../../../utils/settings-search";
import { MOCK_BILLING_INFO } from "../../constants";
import { CurrentPlanCard } from "./components/CurrentPlanCard";
import { InvoicesSection } from "./components/InvoicesSection";
import { UpgradeCard } from "./components/UpgradeCard";

interface BillingOverviewProps {
visibleItems?: SettingItemId[] | null;
}

export function BillingOverview({ visibleItems }: BillingOverviewProps) {
const billingInfo = MOCK_BILLING_INFO;
const showOverview = isItemVisible(
SETTING_ITEM_ID.BILLING_OVERVIEW,
visibleItems,
);
const showInvoices = isItemVisible(
SETTING_ITEM_ID.BILLING_INVOICES,
visibleItems,
);

return (
<div className="p-6 max-w-4xl w-full">
<div className="mb-6">
<div className="flex items-center justify-between">
<div>
<h2 className="text-lg font-semibold">Billing</h2>
<p className="text-xs text-muted-foreground mt-0.5">
For questions about billing,{" "}
<a
href="mailto:founders@superset.sh"
className="text-primary hover:underline"
>
contact us
</a>
</p>
</div>
<Button variant="ghost" size="sm" asChild>
<Link to="/settings/billing/plans">
All plans
<HiArrowRight className="h-3 w-3" />
</Link>
</Button>
</div>
</div>

<div className="space-y-3">
{showOverview && (
<>
<CurrentPlanCard billingInfo={billingInfo} />
{billingInfo.currentPlan === "free" && <UpgradeCard />}
</>
)}

{showInvoices && (
<div className="mt-6">
<InvoicesSection />
</div>
)}
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Badge } from "@superset/ui/badge";
import { Card, CardContent } from "@superset/ui/card";
import type { BillingInfo } from "../../../../constants";
import { PLANS } from "../../../../constants";

interface CurrentPlanCardProps {
billingInfo: BillingInfo;
}

export function CurrentPlanCard({ billingInfo }: CurrentPlanCardProps) {
const plan = PLANS[billingInfo.currentPlan];

return (
<Card className="gap-0 rounded-lg border-border/60 py-0 shadow-none">
<CardContent className="px-5 py-4">
<div className="flex items-center justify-between">
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2 mb-1">
<span className="text-sm font-medium">{plan.name} plan</span>
<Badge variant="secondary">Current</Badge>
</div>
<p className="text-xs text-muted-foreground">{plan.description}</p>
</div>
<div className="ml-6 text-right flex-shrink-0">
<div className="text-[11px] text-muted-foreground mb-0.5">
Users
</div>
<div className="text-sm font-medium">{billingInfo.usage.users}</div>
</div>
</div>
</CardContent>
</Card>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { CurrentPlanCard } from "./CurrentPlanCard";
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Card, CardContent } from "@superset/ui/card";

export function InvoicesSection() {
return (
<div className="space-y-3">
<h3 className="text-sm font-medium">Recent invoices</h3>
<Card className="gap-0 rounded-lg border-border/60 py-0 shadow-none">
<CardContent className="px-5 py-4">
<p className="text-xs text-muted-foreground">No invoices yet</p>
</CardContent>
</Card>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { InvoicesSection } from "./InvoicesSection";
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Button } from "@superset/ui/button";
import { Card, CardContent } from "@superset/ui/card";
import { toast } from "@superset/ui/sonner";
import { Link } from "@tanstack/react-router";
import { HiCheck } from "react-icons/hi2";
import { PLANS } from "../../../../constants";

export function UpgradeCard() {
const plan = PLANS.pro;

const handleUpgrade = () => {
toast.info("Stripe integration coming soon");
};

return (
<Card className="gap-0 rounded-lg border-border/60 py-0 shadow-none">
<CardContent className="px-5 py-4">
<div className="flex flex-wrap items-center justify-between gap-4">
<div>
<div className="text-sm font-medium">
Upgrade to {plan.name} plan
</div>
<p className="text-xs text-muted-foreground">
${plan.price?.monthly ? plan.price.monthly / 100 : 0} per user/mo
</p>
</div>
<div className="flex items-center gap-3">
<Button variant="ghost" size="sm" asChild>
<Link to="/settings/billing/plans">View all plans</Link>
</Button>
<Button onClick={handleUpgrade} size="sm">
Upgrade now
</Button>
</div>
</div>

<div className="my-3 h-px bg-border/60" />

<div className="grid gap-x-4 gap-y-2 text-xs sm:grid-cols-2 lg:grid-cols-3">
{plan.features.map((feature) => (
<div key={feature.id} className="flex items-center gap-2">
<HiCheck className="h-3.5 w-3.5 text-accent-foreground flex-shrink-0" />
<span className="leading-tight">{feature.name}</span>
</div>
))}
</div>
</CardContent>
</Card>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { UpgradeCard } from "./UpgradeCard";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { BillingOverview } from "./BillingOverview";
Loading
Loading