| 'use client'; |
|
|
| import Link from 'next/link'; |
| import { Button } from '@/components/ui/button'; |
| import { Badge } from '@/components/ui/badge'; |
| import { |
| Sparkles, |
| ArrowRight, |
| ArrowLeft, |
| Check, |
| Zap, |
| Crown, |
| Building2, |
| HelpCircle, |
| } from 'lucide-react'; |
| import { useState } from 'react'; |
| import { cn } from '@/lib/utils'; |
|
|
| const plans = [ |
| { |
| name: 'Free', |
| price: 0, |
| yearlyPrice: 0, |
| description: 'Try ScanMenu for free with basic features.', |
| icon: Sparkles, |
| features: [ |
| '1 restaurant', |
| 'Up to 15 menu items', |
| '2 QR codes', |
| 'Basic ordering', |
| '50 orders/month', |
| 'Community support', |
| ], |
| cta: 'Get Started', |
| popular: false, |
| }, |
| { |
| name: 'Starter', |
| price: 29, |
| yearlyPrice: 24, |
| description: 'Perfect for small restaurants just getting started.', |
| icon: Zap, |
| features: [ |
| '1 restaurant', |
| 'Up to 50 menu items', |
| '10 QR codes', |
| 'Dine-in + Takeaway', |
| 'Basic analytics', |
| 'Email support', |
| '500 orders/month', |
| 'Custom branding', |
| ], |
| cta: 'Start Trial', |
| popular: false, |
| }, |
| { |
| name: 'Pro', |
| price: 79, |
| yearlyPrice: 66, |
| description: 'For growing restaurants with advanced needs.', |
| icon: Crown, |
| features: [ |
| 'Unlimited restaurants', |
| 'Unlimited menu items', |
| 'Unlimited QR codes', |
| 'Dine-in + Takeaway + Delivery', |
| 'Advanced analytics', |
| 'Priority support', |
| 'Unlimited orders', |
| 'Custom branding', |
| 'API access', |
| 'Team members (up to 10)', |
| 'Real-time order tracking', |
| 'Product options & extras', |
| ], |
| cta: 'Start Trial', |
| popular: true, |
| }, |
| { |
| name: 'Enterprise', |
| price: 199, |
| yearlyPrice: 166, |
| description: 'For multi-location chains and franchises.', |
| icon: Building2, |
| features: [ |
| 'Everything in Pro', |
| 'Multi-location dashboard', |
| 'Unlimited team members', |
| 'Dedicated account manager', |
| 'Custom integrations', |
| '99.9% SLA guarantee', |
| 'White-label solution', |
| 'Onboarding training', |
| 'Advanced security', |
| 'Custom API limits', |
| 'Phone support', |
| 'Invoice billing', |
| ], |
| cta: 'Contact Sales', |
| popular: false, |
| }, |
| ]; |
|
|
| const faq = [ |
| { q: 'Can I try ScanMenu for free?', a: 'Yes! Our Free plan lets you try ScanMenu with basic features at no cost. We also offer a 14-day free trial on all paid plans β no credit card required.' }, |
| { q: 'How do QR codes work?', a: 'Each QR code is linked to a specific table or order type (takeaway/delivery). Customers scan with their phone camera and instantly see your menu β no app download needed.' }, |
| { q: 'Can I switch plans later?', a: 'Absolutely! You can upgrade or downgrade your plan at any time. Changes take effect at the start of your next billing cycle, and we prorate any differences.' }, |
| { q: 'Do customers need to install an app?', a: 'No! That\'s the beauty of ScanMenu. Customers simply scan a QR code and your menu opens in their phone\'s browser. Zero friction, zero downloads.' }, |
| { q: 'What payment methods do you accept?', a: 'We accept all major credit cards (Visa, Mastercard, Amex, Discover) through Stripe. Enterprise customers can also pay via invoice.' }, |
| { q: 'Is my data secure?', a: 'Yes. We use Supabase (built on PostgreSQL) with row-level security, SSL encryption, and regular backups. Your data is safe and compliant.' }, |
| ]; |
|
|
| export default function PricingPage() { |
| const [annual, setAnnual] = useState(false); |
| const [openFaq, setOpenFaq] = useState<number | null>(0); |
|
|
| return ( |
| <div className="min-h-screen bg-white dark:bg-zinc-950"> |
| {/* Nav */} |
| <nav className="border-b border-zinc-200/50 bg-white/80 backdrop-blur-xl dark:border-zinc-800/50 dark:bg-zinc-950/80"> |
| <div className="mx-auto flex h-16 max-w-6xl items-center justify-between px-4 sm:px-6"> |
| <Link href="/" className="flex items-center gap-2.5"> |
| <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-emerald-500 to-cyan-500 shadow-sm"> |
| <Sparkles className="h-4 w-4 text-white" /> |
| </div> |
| <span className="text-lg font-bold tracking-tight">Scan<span className="text-emerald-600">Menu</span></span> |
| </Link> |
| <div className="flex items-center gap-3"> |
| <Link href="/login"><Button variant="ghost" size="sm">Sign In</Button></Link> |
| <Link href="/register"><Button variant="primary" size="sm">Get Started</Button></Link> |
| </div> |
| </div> |
| </nav> |
| |
| {/* Header */} |
| <section className="pt-16 pb-8 text-center"> |
| <div className="mx-auto max-w-3xl px-4"> |
| <Badge variant="outline" className="mb-4">Pricing</Badge> |
| <h1 className="text-4xl font-bold tracking-tight text-zinc-900 sm:text-5xl dark:text-white"> |
| Simple, transparent pricing |
| </h1> |
| <p className="mt-4 text-lg text-zinc-600 dark:text-zinc-400"> |
| Choose the plan that fits your restaurant. Upgrade, downgrade, or cancel anytime. |
| </p> |
| </div> |
| </section> |
| |
| {/* Toggle */} |
| <div className="flex items-center justify-center gap-3 pb-12"> |
| <span className={cn('text-sm font-medium transition-colors', !annual ? 'text-zinc-900' : 'text-zinc-500')}>Monthly</span> |
| <button |
| onClick={() => setAnnual(!annual)} |
| className={cn('relative h-6 w-11 rounded-full transition-colors', annual ? 'bg-emerald-500' : 'bg-zinc-300')} |
| > |
| <span className={cn('absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white shadow transition-transform', annual && 'translate-x-5')} /> |
| </button> |
| <span className={cn('text-sm font-medium transition-colors', annual ? 'text-zinc-900' : 'text-zinc-500')}> |
| Annual <Badge variant="success" className="ml-1 text-[10px]">Save 17%</Badge> |
| </span> |
| </div> |
| |
| {/* Plans */} |
| <section className="pb-20"> |
| <div className="mx-auto max-w-6xl px-4 sm:px-6"> |
| <div className="grid gap-6 lg:grid-cols-4"> |
| {plans.map((plan) => ( |
| <div |
| key={plan.name} |
| className={cn( |
| 'relative flex flex-col rounded-2xl border bg-white p-6 transition-all hover:shadow-lg dark:bg-zinc-900', |
| plan.popular |
| ? 'border-emerald-500 shadow-lg ring-1 ring-emerald-500/20' |
| : 'border-zinc-200 dark:border-zinc-800' |
| )} |
| > |
| {plan.popular && ( |
| <div className="absolute -top-3 left-1/2 -translate-x-1/2"> |
| <Badge className="bg-emerald-500 text-white border-0 px-3 py-1">Most Popular</Badge> |
| </div> |
| )} |
| |
| <div className="mb-6"> |
| <div className="flex items-center gap-2 mb-3"> |
| <div className={cn( |
| 'flex h-9 w-9 items-center justify-center rounded-xl', |
| plan.popular ? 'bg-emerald-100 text-emerald-600' : 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800' |
| )}> |
| <plan.icon className="h-4 w-4" /> |
| </div> |
| <h3 className="text-lg font-bold">{plan.name}</h3> |
| </div> |
| <p className="text-sm text-zinc-500 mb-4">{plan.description}</p> |
| <div className="flex items-baseline gap-1"> |
| <span className="text-4xl font-bold text-zinc-900 dark:text-white"> |
| ${annual ? plan.yearlyPrice : plan.price} |
| </span> |
| {plan.price > 0 && <span className="text-zinc-500">/month</span>} |
| </div> |
| {annual && plan.price > 0 && ( |
| <p className="mt-1 text-xs text-emerald-600"> |
| ${plan.yearlyPrice * 12}/year (save ${(plan.price - plan.yearlyPrice) * 12}) |
| </p> |
| )} |
| </div> |
| |
| <Link href="/register" className="block mb-6"> |
| <Button |
| variant={plan.popular ? 'primary' : 'outline'} |
| className="w-full" |
| > |
| {plan.cta} {plan.price > 0 && <ArrowRight className="h-4 w-4" />} |
| </Button> |
| </Link> |
| |
| <div className="flex-1 space-y-3"> |
| {plan.features.map((feature) => ( |
| <div key={feature} className="flex items-start gap-2 text-sm"> |
| <Check className={cn('h-4 w-4 shrink-0 mt-0.5', plan.popular ? 'text-emerald-500' : 'text-zinc-400')} /> |
| <span className="text-zinc-600 dark:text-zinc-400">{feature}</span> |
| </div> |
| ))} |
| </div> |
| </div> |
| ))} |
| </div> |
| </div> |
| </section> |
| |
| {/* FAQ */} |
| <section className="border-t border-zinc-200 bg-zinc-50 py-20 dark:border-zinc-800 dark:bg-zinc-900/50"> |
| <div className="mx-auto max-w-3xl px-4 sm:px-6"> |
| <div className="text-center mb-12"> |
| <Badge variant="outline" className="mb-4">FAQ</Badge> |
| <h2 className="text-3xl font-bold tracking-tight text-zinc-900 dark:text-white">Frequently asked questions</h2> |
| </div> |
| |
| <div className="space-y-3"> |
| {faq.map((item, i) => ( |
| <div key={i} className="rounded-2xl border border-zinc-200 bg-white overflow-hidden dark:border-zinc-800 dark:bg-zinc-900"> |
| <button |
| onClick={() => setOpenFaq(openFaq === i ? null : i)} |
| className="flex w-full items-center justify-between p-5 text-left" |
| > |
| <span className="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{item.q}</span> |
| <HelpCircle className={cn('h-4 w-4 shrink-0 text-zinc-400 transition-transform', openFaq === i && 'rotate-180')} /> |
| </button> |
| {openFaq === i && ( |
| <div className="px-5 pb-5 pt-0"> |
| <p className="text-sm leading-relaxed text-zinc-500">{item.a}</p> |
| </div> |
| )} |
| </div> |
| ))} |
| </div> |
| </div> |
| </section> |
| |
| {/* Footer CTA */} |
| <section className="py-16 text-center"> |
| <div className="mx-auto max-w-2xl px-4"> |
| <h2 className="text-2xl font-bold text-zinc-900 dark:text-white">Still have questions?</h2> |
| <p className="mt-2 text-zinc-500">We're here to help. Contact our team for a personalized demo.</p> |
| <div className="mt-6 flex justify-center gap-3"> |
| <Link href="/register"><Button variant="primary">Start Free Trial</Button></Link> |
| <Button variant="outline">Contact Sales</Button> |
| </div> |
| </div> |
| </section> |
| </div> |
| ); |
| } |
|
|