'use client'; import { Check, Crown, Rocket, Shield, X, Zap } from 'lucide-react'; import { useTranslations } from 'next-intl'; import { useState } from 'react'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Link } from '@/i18n/navigation'; import { formatVND } from '@/lib/currency'; import { usePlans } from '@/lib/hooks/use-subscription'; import type { PlanDto } from '@/lib/subscription-api'; import { cn } from '@/lib/utils'; // --------------------------------------------------------------------------- // Constants // --------------------------------------------------------------------------- const PLAN_TIER_ORDER = ['FREE', 'AGENT_PRO', 'INVESTOR', 'ENTERPRISE']; const TIER_ICONS: Record = { FREE: , AGENT_PRO: , INVESTOR: , ENTERPRISE: , }; const TIER_COLORS: Record = { FREE: 'text-muted-foreground', AGENT_PRO: 'text-blue-600', INVESTOR: 'text-purple-600', ENTERPRISE: 'text-amber-600', }; /** Fallback data when API is unavailable */ const FALLBACK_PLANS: PlanDto[] = [ { id: 'fallback-free', tier: 'FREE', name: 'Miễn phí', priceMonthlyVND: '0', priceYearlyVND: '0', maxListings: 3, maxSavedSearches: 5, features: { basicSearch: true, listingPost: true, maxPhotos: 5, analytics: false, prioritySupport: false, aiValuation: false, featuredListing: false, }, isActive: true, }, { id: 'fallback-agent', tier: 'AGENT_PRO', name: 'Agent Pro', priceMonthlyVND: '499000', priceYearlyVND: '4990000', maxListings: 50, maxSavedSearches: 30, features: { basicSearch: true, listingPost: true, maxPhotos: 30, analytics: true, prioritySupport: true, aiValuation: true, featuredListing: true, leadManagement: true, agentProfile: true, }, isActive: true, }, { id: 'fallback-investor', tier: 'INVESTOR', name: 'Investor', priceMonthlyVND: '999000', priceYearlyVND: '9990000', maxListings: 20, maxSavedSearches: 100, features: { basicSearch: true, listingPost: true, maxPhotos: 15, analytics: true, prioritySupport: true, aiValuation: true, featuredListing: false, marketReports: true, priceAlerts: true, portfolioTracking: true, }, isActive: true, }, { id: 'fallback-enterprise', tier: 'ENTERPRISE', name: 'Enterprise', priceMonthlyVND: '4990000', priceYearlyVND: '49900000', maxListings: -1, maxSavedSearches: -1, features: { basicSearch: true, listingPost: true, maxPhotos: 100, analytics: true, prioritySupport: true, aiValuation: true, featuredListing: true, leadManagement: true, agentProfile: true, marketReports: true, priceAlerts: true, portfolioTracking: true, apiAccess: true, whiteLabel: true, dedicatedSupport: true, }, isActive: true, }, ]; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- // Feature labels mapped for the comparison table const FEATURE_LABELS: Record = { maxListings: 'Tin đăng', maxSavedSearches: 'Tìm kiếm đã lưu', maxPhotos: 'Ảnh/tin đăng', analytics: 'Phân tích thị trường', prioritySupport: 'Hỗ trợ ưu tiên', aiValuation: 'Định giá AI', featuredListing: 'Tin đăng nổi bật', leadManagement: 'Quản lý khách hàng', agentProfile: 'Hồ sơ môi giới', marketReports: 'Báo cáo thị trường', priceAlerts: 'Cảnh báo giá', portfolioTracking: 'Theo dõi danh mục', apiAccess: 'Truy cập API', whiteLabel: 'Giao diện riêng', dedicatedSupport: 'Hỗ trợ chuyên biệt', }; const COMPARISON_FEATURES = [ 'maxListings', 'maxSavedSearches', 'maxPhotos', 'analytics', 'aiValuation', 'featuredListing', 'prioritySupport', 'leadManagement', 'agentProfile', 'marketReports', 'priceAlerts', 'portfolioTracking', 'apiAccess', 'whiteLabel', 'dedicatedSupport', ]; function getFeatureValue( plan: PlanDto, key: string, ): boolean | number | string { if (key === 'maxListings') { return plan.maxListings === -1 ? 'Không giới hạn' : plan.maxListings; } if (key === 'maxSavedSearches') { return plan.maxSavedSearches === -1 ? 'Không giới hạn' : plan.maxSavedSearches; } if (key === 'maxPhotos') { return plan.features['maxPhotos'] ?? false; } return plan.features[key] ?? false; } // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- export default function PricingPage() { const t = useTranslations('pricing'); const { data: plansData, isLoading, error } = usePlans(); const [billingCycle, setBillingCycle] = useState<'monthly' | 'yearly'>( 'monthly', ); const plans = (plansData ?? (error ? FALLBACK_PLANS : [])) .slice() .sort( (a, b) => PLAN_TIER_ORDER.indexOf(a.tier) - PLAN_TIER_ORDER.indexOf(b.tier), ); return (
{/* Hero section */}
{t('badge')}

{t('title')}

{t('subtitle')}

{/* Billing cycle toggle */}
{/* Pricing cards */}
{isLoading ? (
{t('loading')}
) : (
{plans.map((plan) => { const isPopular = plan.tier === 'AGENT_PRO'; const price = billingCycle === 'monthly' ? plan.priceMonthlyVND : plan.priceYearlyVND; return ( {isPopular && (
{t('popular')}
)}
{TIER_ICONS[plan.tier]} {t(`tiers.${plan.tier}`)}
{t(`tierDescriptions.${plan.tier}`)}
{/* Price */}
{formatVND(price)} {Number(price) > 0 && ( /{billingCycle === 'monthly' ? t('perMonth') : t('perYear')} )}
{/* Key features list */}
  • {plan.maxListings === -1 ? t('unlimited') : `${plan.maxListings} ${t('listingsCount')}`}
  • {plan.maxSavedSearches === -1 ? t('unlimited') : `${plan.maxSavedSearches} ${t('savedSearchesCount')}`}
  • {plan.features['maxPhotos']} {t('photosPerListing')}
  • {plan.features['analytics'] && (
  • {t('features.analytics')}
  • )} {plan.features['aiValuation'] && (
  • {t('features.aiValuation')}
  • )} {plan.features['prioritySupport'] && (
  • {t('features.prioritySupport')}
  • )} {plan.features['featuredListing'] && (
  • {t('features.featuredListing')}
  • )} {plan.features['leadManagement'] && (
  • {t('features.leadManagement')}
  • )} {plan.features['marketReports'] && (
  • {t('features.marketReports')}
  • )} {plan.features['portfolioTracking'] && (
  • {t('features.portfolioTracking')}
  • )} {plan.features['apiAccess'] && (
  • {t('features.apiAccess')}
  • )}
{/* CTA */}
); })}
)}
{/* Feature comparison table */}

{t('comparisonTitle')}

{t('comparisonSubtitle')}

{plans.map((plan) => ( ))} {COMPARISON_FEATURES.map((featureKey) => ( {plans.map((plan) => { const val = getFeatureValue(plan, featureKey); return ( ); })} ))}
{t('feature')} {t(`tiers.${plan.tier}`)}
{FEATURE_LABELS[featureKey]} {typeof val === 'boolean' ? ( val ? ( ) : ( ) ) : ( {String(val)} )}
{/* FAQ / CTA section */}

{t('ctaTitle')}

{t('ctaDescription')}

); }