HamzaAri's picture
🚀 Deploy ScanMenu - Production-ready SaaS web app for digital restaurant menus & QR ordering
e1ef9fc verified
Raw
History Blame Contribute Delete
9.28 kB
'use client';
import { DashboardLayout } from '@/components/layout/dashboard-layout';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Check, Sparkles, CreditCard, Download, ArrowRight, Zap, Crown, Building2 } from 'lucide-react';
import { cn } from '@/lib/utils';
import { useState } from 'react';
const plans = [
{
name: 'Starter',
price: 29,
yearlyPrice: 24,
description: 'Perfect for small restaurants just getting started.',
icon: Zap,
features: ['1 restaurant', 'Up to 50 menu items', '5 QR codes', 'Basic analytics', 'Email support', '100 orders/month'],
popular: false,
current: 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', 'Advanced analytics', 'Priority support', 'Unlimited orders', 'Custom branding', 'API access', 'Team members'],
popular: true,
current: true,
},
{
name: 'Enterprise',
price: 199,
yearlyPrice: 166,
description: 'For multi-location chains and franchises.',
icon: Building2,
features: ['Everything in Pro', 'Multi-location support', 'Dedicated account manager', 'Custom integrations', 'SLA guarantee', 'White-label solution', 'Advanced security', 'Onboarding training'],
popular: false,
current: false,
},
];
const invoices = [
{ id: 'INV-2024-003', date: 'Mar 1, 2025', amount: 79, status: 'paid' },
{ id: 'INV-2024-002', date: 'Feb 1, 2025', amount: 79, status: 'paid' },
{ id: 'INV-2024-001', date: 'Jan 1, 2025', amount: 79, status: 'paid' },
];
export default function BillingPage() {
const [annual, setAnnual] = useState(false);
return (
<DashboardLayout>
<div className="space-y-8">
{/* Header */}
<div>
<h1 className="text-2xl font-bold tracking-tight text-zinc-900 dark:text-white sm:text-3xl">Billing & Subscription</h1>
<p className="mt-1 text-sm text-zinc-500">Manage your plan, payment methods, and invoices.</p>
</div>
{/* Current Plan Banner */}
<div className="relative overflow-hidden rounded-2xl bg-gradient-to-r from-emerald-600 via-emerald-500 to-cyan-500 p-6 text-white shadow-lg sm:p-8">
<div className="relative z-10">
<Badge className="bg-white/20 text-white border-white/30 mb-3">Current Plan</Badge>
<h2 className="text-2xl font-bold">Pro Plan</h2>
<p className="mt-1 text-emerald-100">Your next billing date is April 1, 2025</p>
<div className="mt-4 flex items-baseline gap-1">
<span className="text-4xl font-bold">$79</span>
<span className="text-emerald-200">/month</span>
</div>
</div>
<div className="absolute -right-8 -top-8 h-40 w-40 rounded-full bg-white/10" />
<div className="absolute -bottom-12 -right-12 h-48 w-48 rounded-full bg-white/5" />
</div>
{/* Billing Toggle */}
<div className="flex items-center justify-center gap-3">
<span className={cn('text-sm font-medium', !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 dark:bg-zinc-600'
)}
>
<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', annual ? 'text-zinc-900' : 'text-zinc-500')}>
Annual <Badge variant="success" className="ml-1 text-[10px]">Save 17%</Badge>
</span>
</div>
{/* Plans */}
<div className="grid gap-6 lg:grid-cols-3">
{plans.map((plan) => (
<Card key={plan.name} className={cn(
'relative overflow-hidden transition-all hover:shadow-lg',
plan.popular && 'border-emerald-500 shadow-md ring-1 ring-emerald-500/20',
plan.current && 'border-emerald-500'
)}>
{plan.popular && (
<div className="absolute -right-8 top-6 rotate-45 bg-emerald-500 px-10 py-1 text-[10px] font-bold uppercase tracking-wider text-white shadow-sm">
Popular
</div>
)}
<CardContent className="pt-6 space-y-6">
<div>
<div className="flex items-center gap-2">
<div className={cn(
'flex h-10 w-10 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-5 w-5" />
</div>
<div>
<h3 className="text-lg font-bold text-zinc-900 dark:text-zinc-100">{plan.name}</h3>
</div>
</div>
<p className="mt-2 text-sm text-zinc-500">{plan.description}</p>
</div>
<div className="flex items-baseline gap-1">
<span className="text-4xl font-bold text-zinc-900 dark:text-zinc-100">
${annual ? plan.yearlyPrice : plan.price}
</span>
<span className="text-zinc-500">/month</span>
</div>
<Button
variant={plan.current ? 'outline' : plan.popular ? 'primary' : 'default'}
className="w-full"
disabled={plan.current}
>
{plan.current ? 'Current Plan' : 'Upgrade'}
{!plan.current && <ArrowRight className="h-4 w-4" />}
</Button>
<div className="space-y-3">
{plan.features.map((feature) => (
<div key={feature} className="flex items-center gap-2 text-sm">
<Check className={cn(
'h-4 w-4 shrink-0',
plan.popular ? 'text-emerald-500' : 'text-zinc-400'
)} />
<span className="text-zinc-600 dark:text-zinc-400">{feature}</span>
</div>
))}
</div>
</CardContent>
</Card>
))}
</div>
{/* Payment Method & Invoices */}
<div className="grid gap-6 lg:grid-cols-2">
{/* Payment Method */}
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Payment Method</CardTitle>
<Button variant="outline" size="sm">Update</Button>
</CardHeader>
<CardContent>
<div className="flex items-center gap-4 rounded-xl border border-zinc-200 p-4 dark:border-zinc-700">
<div className="flex h-12 w-16 items-center justify-center rounded-lg bg-gradient-to-br from-blue-600 to-blue-800">
<CreditCard className="h-6 w-6 text-white" />
</div>
<div>
<p className="text-sm font-medium text-zinc-900 dark:text-zinc-100">Visa ending in 4242</p>
<p className="text-xs text-zinc-500">Expires 12/2026</p>
</div>
<Badge variant="success" className="ml-auto text-[10px]">Default</Badge>
</div>
</CardContent>
</Card>
{/* Recent Invoices */}
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Recent Invoices</CardTitle>
<Button variant="ghost" size="sm" className="text-xs">View All</Button>
</CardHeader>
<CardContent>
<div className="space-y-3">
{invoices.map((invoice) => (
<div key={invoice.id} className="flex items-center justify-between rounded-xl border border-zinc-100 p-3 dark:border-zinc-800">
<div>
<p className="text-sm font-medium text-zinc-900 dark:text-zinc-100">{invoice.id}</p>
<p className="text-xs text-zinc-500">{invoice.date}</p>
</div>
<div className="flex items-center gap-3">
<span className="text-sm font-semibold">${invoice.amount}</span>
<Badge variant="success" className="text-[10px]">{invoice.status}</Badge>
<Button variant="ghost" size="icon-sm">
<Download className="h-3.5 w-3.5" />
</Button>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
</div>
</DashboardLayout>
);
}