"use client";
import { useState } from "react";
import {
Settings,
CreditCard,
Calendar,
Zap,
Users,
HardDrive,
ArrowUpRight,
FileText,
RefreshCw,
AlertCircle,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Progress } from "@/components/ui/progress";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
type UsageStat = {
id: string;
label: string;
used: number;
limit: number;
unit: string;
icon: React.ElementType;
};
const usageStats: UsageStat[] = [
{ id: "projects", label: "Projects", used: 8, limit: 10, unit: "", icon: Zap },
{ id: "members", label: "Team Members", used: 4, limit: 5, unit: "", icon: Users },
{ id: "storage", label: "Storage", used: 12.4, limit: 25, unit: "GB", icon: HardDrive },
];
export const title = "React Dialog Block Manage Subscription";
export default function DialogManageSubscription() {
const [open, setOpen] = useState(false);
const plan = {
name: "Pro",
price: 29,
interval: "month",
status: "active",
nextBilling: "January 15, 2025",
paymentMethod: {
type: "visa",
last4: "4242",
},
};
const getUsagePercentage = (used: number, limit: number) => {
return Math.min((used / limit) * 100, 100);
};
const getUsageColor = (percentage: number) => {
if (percentage >= 90) return "text-destructive";
if (percentage >= 75) return "text-yellow-600";
return "text-muted-foreground";
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<Settings className="mr-2 h-4 w-4" />
Manage Subscription
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Settings className="h-5 w-5" />
Subscription
</DialogTitle>
<DialogDescription>
Manage your plan, usage, and billing settings.
</DialogDescription>
</DialogHeader>
<div className="space-y-6 py-4">
{/* Current Plan */}
<div className="rounded-lg border p-4">
<div className="flex items-start justify-between">
<div>
<div className="flex items-center gap-2">
<h3 className="font-semibold">{plan.name} Plan</h3>
<Badge variant="secondary" className="text-xs">
{plan.status === "active" ? "Active" : "Inactive"}
</Badge>
</div>
<p className="text-2xl font-bold mt-1">
${plan.price}
<span className="text-sm font-normal text-muted-foreground">
/{plan.interval}
</span>
</p>
</div>
<Button variant="outline" size="sm">
<ArrowUpRight className="mr-1 h-3 w-3" />
Upgrade
</Button>
</div>
<Separator className="my-4" />
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2 text-muted-foreground">
<Calendar className="h-4 w-4" />
<span>Next billing: {plan.nextBilling}</span>
</div>
<Button variant="link" size="sm" className="h-auto p-0 text-xs">
Change cycle
</Button>
</div>
</div>
{/* Usage Stats */}
<div className="space-y-3">
<div className="flex items-center justify-between">
<h4 className="text-sm font-medium">Usage</h4>
<span className="text-xs text-muted-foreground">
Resets monthly
</span>
</div>
<div className="space-y-4">
{usageStats.map((stat) => {
const percentage = getUsagePercentage(stat.used, stat.limit);
const Icon = stat.icon;
const colorClass = getUsageColor(percentage);
return (
<div key={stat.id} className="space-y-1.5">
<div className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2">
<Icon className="h-4 w-4 text-muted-foreground" />
<span>{stat.label}</span>
</div>
<span className={cn("text-xs", colorClass)}>
{stat.used}{stat.unit} / {stat.limit}{stat.unit}
</span>
</div>
<Progress
value={percentage}
className={cn(
"h-2",
percentage >= 90 && "[&>div]:bg-destructive",
percentage >= 75 && percentage < 90 && "[&>div]:bg-yellow-500"
)}
/>
</div>
);
})}
</div>
{usageStats.some(
(stat) => getUsagePercentage(stat.used, stat.limit) >= 75
) && (
<div className="flex items-start gap-2 rounded-lg border border-yellow-500/50 p-3 text-sm">
<AlertCircle className="h-4 w-4 text-yellow-600 mt-0.5" />
<div>
<p className="font-medium">Approaching limits</p>
<p className="text-xs text-muted-foreground">
Consider upgrading to avoid service interruptions.
</p>
</div>
</div>
)}
</div>
<Separator />
{/* Payment Method */}
<div className="space-y-3">
<h4 className="text-sm font-medium">Payment Method</h4>
<div className="flex items-center justify-between rounded-lg border p-3">
<div className="flex items-center gap-3">
<div className="flex h-10 w-14 items-center justify-center rounded border">
{plan.paymentMethod.type === "visa" && (
<span className="text-xs font-bold italic text-blue-600">VISA</span>
)}
</div>
<div>
<p className="text-sm font-medium">
•••• •••• •••• {plan.paymentMethod.last4}
</p>
<p className="text-xs text-muted-foreground">
Expires 12/25
</p>
</div>
</div>
<Button variant="ghost" size="sm">
<CreditCard className="mr-1 h-3 w-3" />
Change
</Button>
</div>
</div>
{/* Quick Actions */}
<div className="grid grid-cols-2 gap-2">
<Button variant="outline" size="sm" className="justify-start">
<FileText className="mr-2 h-4 w-4" />
View Invoices
</Button>
<Button variant="outline" size="sm" className="justify-start">
<RefreshCw className="mr-2 h-4 w-4" />
Change Billing
</Button>
</div>
</div>
<div className="flex items-center justify-between pt-2 border-t">
<Button
variant="ghost"
size="sm"
className="text-muted-foreground hover:text-destructive"
>
Cancel Subscription
</Button>
<Button onClick={() => setOpen(false)}>Done</Button>
</div>
</DialogContent>
</Dialog>
);
}