60 lines
1.8 KiB
TypeScript
60 lines
1.8 KiB
TypeScript
"use client";
|
||
|
||
import { cn } from "@/lib/utils";
|
||
import { Badge } from "@/components/ui/badge";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Crown, ArrowUpRight } from "lucide-react";
|
||
import Link from "next/link";
|
||
|
||
const PLAN_CONFIG: Record<string, { label: string; variant: "default" | "secondary" | "primary" | "info" }> = {
|
||
free: { label: "免费版", variant: "secondary" },
|
||
starter: { label: "入门版", variant: "info" },
|
||
pro: { label: "专业版", variant: "default" },
|
||
enterprise: { label: "企业版", variant: "primary" },
|
||
};
|
||
|
||
interface SubscriptionStatusProps {
|
||
plan: string;
|
||
expiresAt?: string;
|
||
className?: string;
|
||
}
|
||
|
||
export function SubscriptionStatus({ plan, expiresAt, className }: SubscriptionStatusProps) {
|
||
const config = PLAN_CONFIG[plan] || PLAN_CONFIG.free;
|
||
const showUpgrade = plan === "free" || plan === "starter";
|
||
|
||
const formatDate = (dateStr: string) => {
|
||
try {
|
||
return new Date(dateStr).toLocaleDateString("zh-CN", {
|
||
year: "numeric",
|
||
month: "long",
|
||
day: "numeric",
|
||
});
|
||
} catch {
|
||
return dateStr;
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className={cn("flex items-center gap-3", className)}>
|
||
<div className="flex items-center gap-2">
|
||
{plan !== "free" && <Crown className="h-4 w-4 text-amber-500" />}
|
||
<Badge variant={config.variant}>{config.label}</Badge>
|
||
</div>
|
||
{expiresAt && (
|
||
<span className="text-xs text-muted-foreground">
|
||
到期:{formatDate(expiresAt)}
|
||
</span>
|
||
)}
|
||
{showUpgrade && (
|
||
<Link href="/dashboard/subscription">
|
||
<Button variant="outline" size="sm" className="h-7 text-xs gap-1">
|
||
升级
|
||
<ArrowUpRight className="h-3 w-3" />
|
||
</Button>
|
||
</Link>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|