final prcing fixes

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-13 21:12:36 +00:00
parent 75706e8b05
commit c51270a3be
7 changed files with 129 additions and 49 deletions

View File

@@ -251,6 +251,12 @@ export default function SignUpFormUnified({
};
const extractFeatures = (plan: Plan): string[] => {
// Use features from plan's JSON field if available, otherwise build from limits
if (plan.features && plan.features.length > 0) {
return plan.features;
}
// Fallback to building from plan limits
const features: string[] = [];
features.push(`${plan.max_sites} ${plan.max_sites === 1 ? 'Site' : 'Sites'}`);
features.push(`${plan.max_users} ${plan.max_users === 1 ? 'User' : 'Users'}`);
@@ -628,9 +634,9 @@ export default function SignUpFormUnified({
</div>
</div>
{/* Features - 3 rows x 2 columns = 6 features */}
{/* Features - All features in 2 columns */}
<div className="grid grid-cols-2 gap-x-3 gap-y-2.5">
{features.slice(0, 6).map((feature, idx) => (
{features.map((feature, idx) => (
<div key={idx} className="flex items-start gap-2">
<CheckCircle className="w-4 h-4 text-green-500 dark:text-green-400 flex-shrink-0 mt-0.5" />
<span className="text-sm text-gray-700 dark:text-gray-300 leading-tight">{feature}</span>

View File

@@ -2,6 +2,7 @@ import { useState } from 'react';
export interface PricingPlan {
id?: number;
slug?: string;
name: string;
price: string | number; // Current displayed price (will be calculated based on period)
monthlyPrice?: string | number; // Base monthly price (used for annual discount calculation)
@@ -100,40 +101,40 @@ export default function PricingTable({
)}
{showToggle && (
<div className="mb-8 text-center">
<div className="relative inline-flex p-1 bg-gray-200 rounded-full dark:bg-gray-800 shadow-sm">
<span
className="absolute top-1 left-1 flex h-11 w-[130px] rounded-full shadow-theme-xs duration-200 ease-linear"
style={{
background: 'linear-gradient(to bottom right, #0693e3, #0472b8)',
transform: billingPeriod === 'monthly' ? 'translateX(0)' : 'translateX(130px)',
}}
></span>
<button
type="button"
onClick={() => setBillingPeriod('monthly')}
className={`relative z-10 flex h-11 w-[130px] items-center justify-center font-medium transition-all duration-200 rounded-full ${
billingPeriod === 'monthly'
? 'text-white'
: 'text-gray-500 hover:text-gray-700 dark:hover:text-white/80 dark:text-gray-400'
}`}
>
Monthly
</button>
<button
type="button"
onClick={() => setBillingPeriod('annually')}
className={`relative z-10 flex h-11 w-[130px] items-center justify-center font-medium transition-all duration-200 rounded-full ${
billingPeriod === 'annually'
? 'text-white'
: 'text-gray-500 hover:text-gray-700 dark:hover:text-white/80 dark:text-gray-400'
}`}
>
Annually
</button>
</div>
{billingPeriod === 'annually' && (
<div className="flex items-center justify-center mt-3">
<span className="inline-flex items-center gap-1.5 text-green-600 dark:text-green-400 font-semibold bg-green-50 dark:bg-green-900/20 px-3 py-1.5 rounded-full text-sm">
<div className="relative inline-flex items-center justify-center">
<div className="relative inline-flex p-1 bg-gray-200 rounded-full dark:bg-gray-800 shadow-sm">
<span
className="absolute top-1 left-1 flex h-11 w-[130px] rounded-full shadow-theme-xs duration-200 ease-linear"
style={{
background: 'linear-gradient(to bottom right, #0693e3, #0472b8)',
transform: billingPeriod === 'monthly' ? 'translateX(0)' : 'translateX(130px)',
}}
></span>
<button
type="button"
onClick={() => setBillingPeriod('monthly')}
className={`relative z-10 flex h-11 w-[130px] items-center justify-center font-medium transition-all duration-200 rounded-full cursor-pointer ${
billingPeriod === 'monthly'
? 'text-white'
: 'text-gray-500 hover:text-gray-700 dark:hover:text-white/80 dark:text-gray-400'
}`}
>
Monthly
</button>
<button
type="button"
onClick={() => setBillingPeriod('annually')}
className={`relative z-10 flex h-11 w-[130px] items-center justify-center font-medium transition-all duration-200 rounded-full cursor-pointer ${
billingPeriod === 'annually'
? 'text-white'
: 'text-gray-500 hover:text-gray-700 dark:hover:text-white/80 dark:text-gray-400'
}`}
>
Annually
</button>
</div>
{billingPeriod === 'annually' && (
<span className="absolute left-[calc(100%+1rem)] whitespace-nowrap inline-flex items-center gap-1.5 text-green-600 dark:text-green-400 font-semibold bg-green-50 dark:bg-green-900/20 px-3 py-1.5 rounded-full text-sm">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
@@ -142,13 +143,13 @@ export default function PricingTable({
d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
Save {plans[0]?.annualDiscountPercent || 15}% with annual billing
Save {Math.round(plans[0]?.annualDiscountPercent || 15)}% with annual billing
</span>
</div>
)}
)}
</div>
</div>
)}
<div className="grid gap-5 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 xl:gap-6">
<div className="flex flex-wrap gap-5 xl:gap-6 justify-center max-w-[1660px] mx-auto">
{plans.map((plan, index) => {
const isHighlighted = plan.highlighted || false; // Use explicit highlighted prop
const displayPrice = getDisplayPrice(plan);
@@ -157,7 +158,7 @@ export default function PricingTable({
return (
<div
key={plan.id || index}
className={`rounded-2xl border p-6 flex flex-col ${
className={`rounded-2xl border p-6 flex flex-col flex-1 min-w-[280px] max-w-[380px] ${
isHighlighted
? 'bg-gray-800 border-gray-800 dark:border-white/10 dark:bg-white/10'
: 'border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03]'
@@ -235,7 +236,7 @@ export default function PricingTable({
isHighlighted
? 'bg-brand-500 hover:bg-brand-600 dark:hover:bg-brand-600'
: 'bg-gray-800 hover:bg-brand-500 dark:bg-white/10 dark:hover:bg-brand-600'
} ${plan.disabled ? 'opacity-50 cursor-not-allowed' : ''}`}
} ${plan.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}
>
{plan.buttonText || (plan.price === 0 || plan.monthlyPrice === 0 ? 'Start Free' : 'Choose Plan')}
</button>