billing accoutn with all the mess here

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-05 03:59:54 +00:00
parent 6b291671bd
commit 6cf786b03f
41 changed files with 7257 additions and 685 deletions

View File

@@ -0,0 +1,141 @@
/**
* Pricing Table Component
* Display subscription plans in a table format
*/
import { useState } from 'react';
import { Check } from 'lucide-react';
import Button from '../button/Button';
import Badge from '../badge/Badge';
export interface PricingPlan {
id: number;
name: string;
monthlyPrice: number;
price: number;
period: string;
description: string;
features: string[];
buttonText: string;
highlighted?: boolean;
}
interface PricingTableProps {
variant?: '1' | '2';
title?: string;
plans: PricingPlan[];
showToggle?: boolean;
onPlanSelect?: (plan: PricingPlan) => void;
}
export function PricingTable({ variant = '1', title, plans, showToggle = false, onPlanSelect }: PricingTableProps) {
const [billingPeriod, setBillingPeriod] = useState<'monthly' | 'annual'>('monthly');
const getPrice = (plan: PricingPlan) => {
if (billingPeriod === 'annual') {
return (plan.monthlyPrice * 12 * 0.8).toFixed(0); // 20% discount for annual
}
return plan.monthlyPrice.toFixed(0);
};
const getPeriod = () => {
return billingPeriod === 'annual' ? '/year' : '/month';
};
return (
<div className="w-full">
{title && (
<div className="text-center mb-8">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">{title}</h2>
</div>
)}
{showToggle && (
<div className="flex justify-center mb-8">
<div className="inline-flex items-center gap-3 p-1 bg-gray-100 dark:bg-gray-800 rounded-lg">
<button
onClick={() => setBillingPeriod('monthly')}
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
billingPeriod === 'monthly'
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm'
: 'text-gray-600 dark:text-gray-400'
}`}
>
Monthly
</button>
<button
onClick={() => setBillingPeriod('annual')}
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
billingPeriod === 'annual'
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm'
: 'text-gray-600 dark:text-gray-400'
}`}
>
Annual
<Badge className="ml-2 text-xs" color="success">
Save 20%
</Badge>
</button>
</div>
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{plans.map((plan) => (
<div
key={plan.id}
className={`relative rounded-lg border ${
plan.highlighted
? 'border-primary shadow-lg ring-2 ring-primary ring-opacity-50'
: 'border-gray-200 dark:border-gray-700'
} bg-white dark:bg-gray-800 p-6 flex flex-col`}
>
{plan.highlighted && (
<div className="absolute -top-4 left-1/2 transform -translate-x-1/2">
<Badge color="primary" className="px-3 py-1">
Popular
</Badge>
</div>
)}
<div className="mb-4">
<h3 className="text-xl font-bold text-gray-900 dark:text-white">{plan.name}</h3>
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">{plan.description}</p>
</div>
<div className="mb-6">
<div className="flex items-baseline gap-1">
<span className="text-4xl font-bold text-gray-900 dark:text-white">
${getPrice(plan)}
</span>
<span className="text-gray-600 dark:text-gray-400">{getPeriod()}</span>
</div>
{billingPeriod === 'annual' && plan.monthlyPrice > 0 && (
<p className="text-sm text-gray-500 mt-1">
Billed ${(plan.monthlyPrice * 12 * 0.8).toFixed(0)}/year
</p>
)}
</div>
<ul className="space-y-3 mb-6 flex-grow">
{plan.features.map((feature, index) => (
<li key={index} className="flex items-start gap-2">
<Check className="w-5 h-5 text-green-500 flex-shrink-0 mt-0.5" />
<span className="text-sm text-gray-700 dark:text-gray-300">{feature}</span>
</li>
))}
</ul>
<Button
variant={plan.highlighted ? 'primary' : 'outline'}
className="w-full"
onClick={() => onPlanSelect?.(plan)}
>
{plan.buttonText}
</Button>
</div>
))}
</div>
</div>
);
}