pricign tbale udpated

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-13 19:52:49 +00:00
parent db1fd2fff8
commit 410d2b33ec
12 changed files with 453 additions and 104 deletions

View File

@@ -2,7 +2,8 @@ import { useState, useEffect } from 'react';
import PageMeta from '../../components/common/PageMeta';
import { useToast } from '../../components/ui/toast/ToastContainer';
import { fetchAPI } from '../../services/api';
import { PricingTable, PricingPlan } from '../../components/ui/pricing-table';
import { PricingPlan } from '../../components/ui/pricing-table';
import PricingTable1 from '../../components/ui/pricing-table/pricing-table-1';
interface Plan {
id: number;
@@ -86,7 +87,7 @@ const transformPlanToPricingPlan = (plan: Plan, index: number, totalPlans: numbe
period: '/month',
description: getPlanDescription(plan),
features: extractFeatures(plan),
buttonText: monthlyPrice === 0 ? 'Start Free' : 'Select Plan',
buttonText: monthlyPrice === 0 ? 'Free Trial' : 'Choose Plan',
highlighted: highlighted,
};
};
@@ -94,14 +95,16 @@ const transformPlanToPricingPlan = (plan: Plan, index: number, totalPlans: numbe
// Get plan description based on plan name or features
const getPlanDescription = (plan: Plan): string => {
const slug = plan.slug.toLowerCase();
if (slug.includes('free')) {
return 'Perfect for getting started';
} else if (slug.includes('starter')) {
return 'For solo designers & freelancers';
} else if (slug.includes('growth')) {
return 'For growing businesses';
} else if (slug.includes('scale') || slug.includes('enterprise')) {
return 'For teams and large organizations';
const name = plan.name.toLowerCase();
if (slug.includes('free') || name.includes('free')) {
return 'Explore core features risk free';
} else if (slug.includes('starter') || name.includes('starter')) {
return 'Launch SEO workflows for small teams';
} else if (slug.includes('growth') || name.includes('growth')) {
return 'Scale content production with confidence';
} else if (slug.includes('scale') || slug.includes('enterprise') || name.includes('scale') || name.includes('enterprise')) {
return 'Enterprise power for high volume growth';
}
return 'Choose the perfect plan for your needs';
};
@@ -165,8 +168,7 @@ export default function Plans() {
</div>
) : (
<>
<PricingTable
variant="1"
<PricingTable1
title="Flexible Plans Tailored to Fit Your Unique Needs!"
plans={pricingPlans}
showToggle={true}

View File

@@ -1,6 +1,29 @@
import { useState, useEffect } from "react";
import ComponentCard from "../../../components/common/ComponentCard";
import PageMeta from "../../../components/common/PageMeta";
import { PricingTable, PricingPlan } from "../../../components/ui/pricing-table";
import PricingTable1 from "../../../components/ui/pricing-table/pricing-table-1";
import { getPublicPlans } from "../../../services/billing.api";
interface Plan {
id: number;
name: string;
slug?: string;
price: number | string;
original_price?: number;
annual_discount_percent?: number;
is_featured?: boolean;
max_sites?: number;
max_users?: number;
max_keywords?: number;
max_clusters?: number;
max_content_ideas?: number;
max_content_words?: number;
max_images_basic?: number;
max_images_premium?: number;
max_image_prompts?: number;
included_credits?: number;
}
// Sample icons for variant 2
const PersonIcon = () => (
@@ -21,9 +44,95 @@ const StarIcon = () => (
</svg>
);
const formatNumber = (num: number | undefined | null): string => {
if (!num || num === 0) return '0';
if (num >= 1000000) return `${(num / 1000000).toFixed(0)}M`;
if (num >= 1000) return `${(num / 1000).toFixed(0)}K`;
return num.toString();
};
const convertToPricingPlan = (plan: Plan): PricingPlan => {
const monthlyPrice = typeof plan.price === 'number' ? plan.price : parseFloat(String(plan.price || 0));
const features: string[] = [];
if (plan.max_sites) features.push(`${plan.max_sites === 999999 ? 'Unlimited' : plan.max_sites} Site${plan.max_sites > 1 ? 's' : ''}`);
if (plan.max_users) features.push(`${plan.max_users} Team User${plan.max_users > 1 ? 's' : ''}`);
if (plan.included_credits) features.push(`${formatNumber(plan.included_credits)} Monthly Credits`);
if (plan.max_content_words) features.push(`${formatNumber(plan.max_content_words)} Words/Month`);
if (plan.max_clusters) features.push(`${plan.max_clusters} AI Keyword Clusters`);
if (plan.max_content_ideas) features.push(`${formatNumber(plan.max_content_ideas)} Content Ideas`);
if (plan.max_images_basic && plan.max_images_premium) {
features.push(`${formatNumber(plan.max_images_basic)} Basic / ${formatNumber(plan.max_images_premium)} Premium Images`);
}
if (plan.max_image_prompts) features.push(`${formatNumber(plan.max_image_prompts)} Image Prompts`);
// Custom descriptions based on plan name
let description = `Perfect for ${plan.name.toLowerCase()} needs`;
if (plan.name.toLowerCase().includes('free')) {
description = 'Explore core features risk free';
} else if (plan.name.toLowerCase().includes('starter')) {
description = 'Launch SEO workflows for small teams';
} else if (plan.name.toLowerCase().includes('growth')) {
description = 'Scale content production with confidence';
} else if (plan.name.toLowerCase().includes('scale')) {
description = 'Enterprise power for high volume growth';
}
return {
id: plan.id,
name: plan.name,
monthlyPrice: monthlyPrice,
price: monthlyPrice,
originalPrice: plan.original_price ? (typeof plan.original_price === 'number' ? plan.original_price : parseFloat(String(plan.original_price))) : undefined,
period: '/month',
description: description,
features,
buttonText: monthlyPrice === 0 ? 'Free Trial' : 'Choose Plan',
highlighted: plan.is_featured || false,
annualDiscountPercent: plan.annual_discount_percent || 15,
};
};
export default function PricingTablePage() {
const [backendPlans, setBackendPlans] = useState<Plan[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchPlans = async () => {
try {
const data = await getPublicPlans();
setBackendPlans(data);
setLoading(false);
} catch (err) {
console.error('Error fetching plans:', err);
setError('Failed to load plans');
setLoading(false);
}
};
fetchPlans();
}, []);
// Sample plans for variant 1
const plans1: PricingPlan[] = [
{
id: 0,
name: 'Free Plan',
price: 0.00,
period: '/month',
description: 'Perfect for free plan needs',
features: [
'1 Site',
'1 Team User',
'1K Monthly Credits',
'100K Words/Month',
'100 AI Keyword Clusters',
'300 Content Ideas',
'300 Basic / 60 Premium Images',
'300 Image Prompts',
],
buttonText: 'Start Free',
},
{
id: 1,
name: 'Starter',
@@ -205,10 +314,29 @@ export default function PricingTablePage() {
description="This is React.js Pricing Tables page for TailAdmin - React.js Tailwind CSS Admin Dashboard Template"
/>
<div className="space-y-5 sm:space-y-6">
<ComponentCard title="Pricing Table 1 - Dynamic (Backend Plans)">
{loading && (
<div className="text-center py-12">
<div className="inline-block animate-spin rounded-full h-12 w-12 border-b-2 border-brand-500"></div>
<p className="mt-4 text-gray-600 dark:text-gray-400">Loading backend plans...</p>
</div>
)}
{error && (
<div className="text-center py-12">
<p className="text-red-600">{error}</p>
</div>
)}
{!loading && !error && backendPlans.length > 0 && (
<PricingTable1
plans={backendPlans.map(convertToPricingPlan)}
showToggle={true}
onPlanSelect={(plan) => console.log('Selected backend plan:', plan)}
/>
)}
</ComponentCard>
<ComponentCard title="Pricing Table 1">
<PricingTable
variant="1"
title="Flexible Plans Tailored to Fit Your Unique Needs!"
<PricingTable1
plans={plans1}
showToggle={true}
onPlanSelect={(plan) => console.log('Selected plan:', plan)}

View File

@@ -12,7 +12,8 @@ import { Card } from '../../components/ui/card';
import Badge from '../../components/ui/badge/Badge';
import Button from '../../components/ui/button/Button';
import { useToast } from '../../components/ui/toast/ToastContainer';
import { PricingTable } from '../../components/ui/pricing-table';
import { PricingPlan } from '../../components/ui/pricing-table';
import PricingTable1 from '../../components/ui/pricing-table/pricing-table-1';
import CreditCostBreakdownPanel from '../../components/billing/CreditCostBreakdownPanel';
import CreditCostsPanel from '../../components/billing/CreditCostsPanel';
import UsageLimitsPanel from '../../components/billing/UsageLimitsPanel';
@@ -716,9 +717,9 @@ export default function PlansAndBillingPage() {
Select the plan that best fits your needs
</p>
</div>
<div className="mx-auto" style={{ maxWidth: '1200px' }}>
<PricingTable
variant="1"
<div className="mx-auto" style={{ maxWidth: '1560px' }}>
<PricingTable1
title=""
plans={plans
.filter(plan => {
// Only show paid plans (exclude Free Plan)
@@ -728,29 +729,42 @@ export default function PlansAndBillingPage() {
})
.map(plan => {
const discount = plan.annual_discount_percent || 15;
// Get custom description based on plan name
let description = 'Standard plan';
const planName = plan.name.toLowerCase();
if (planName.includes('starter')) {
description = 'Launch SEO workflows for small teams';
} else if (planName.includes('growth')) {
description = 'Scale content production with confidence';
} else if (planName.includes('scale')) {
description = 'Enterprise power for high volume growth';
}
// Build features array
const features: string[] = [];
if (plan.max_sites) features.push(`${plan.max_sites === 999999 ? 'Unlimited' : plan.max_sites} Site${plan.max_sites > 1 ? 's' : ''}`);
if (plan.max_users) features.push(`${plan.max_users} Team User${plan.max_users > 1 ? 's' : ''}`);
if (plan.included_credits) features.push(`${(plan.included_credits / 1000).toFixed(0)}K Monthly Credits`);
if (plan.max_content_words) features.push(`${(plan.max_content_words / 1000).toFixed(0)}K Words/Month`);
if (plan.max_clusters) features.push(`${plan.max_clusters} AI Keyword Clusters`);
if (plan.max_content_ideas) features.push(`${plan.max_content_ideas} Content Ideas`);
if (plan.max_images_basic && plan.max_images_premium) {
features.push(`${plan.max_images_basic} Basic / ${plan.max_images_premium} Premium Images`);
}
return {
id: plan.id,
name: plan.name,
monthlyPrice: plan.price || 0,
price: plan.price || 0,
annualDiscountPercent: discount,
period: `/${plan.interval || 'month'}`,
description: plan.description || 'Standard plan',
features: plan.features && plan.features.length > 0
? plan.features
: ['Monthly credits included', 'Module access', 'Email support'],
buttonText: plan.id === currentPlanId ? 'Current Plan' : 'Select Plan',
period: '/month',
description: description,
features: features.length > 0 ? features : ['Monthly credits included', 'Module access', 'Email support'],
buttonText: plan.id === currentPlanId ? 'Current Plan' : 'Choose Plan',
highlighted: plan.is_featured || false,
disabled: plan.id === currentPlanId || planLoadingId === plan.id,
max_sites: plan.max_sites,
max_users: plan.max_users,
max_keywords: plan.max_keywords,
max_clusters: plan.max_clusters,
max_content_ideas: plan.max_content_ideas,
max_content_words: plan.max_content_words,
max_images_basic: plan.max_images_basic,
max_images_premium: plan.max_images_premium,
included_credits: plan.included_credits,
};
})}
showToggle={true}