Navbar/Footer: Logo replaces text 'DashCaddy' wordmark, image-only branding Docs: All 7 pages rewritten to comprehensive 200-300 line guides with code examples, callout boxes, reference tables, and cross-page links Stripe: 4 Payment Links wired in (0/30d, 0/90d, 0/180d, 9/365d) Products and Prices created in Stripe Dashboard
301 lines
15 KiB
TypeScript
301 lines
15 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import Link from 'next/link';
|
|
import Navbar from '@/components/Navbar';
|
|
import Footer from '@/components/Footer';
|
|
|
|
// ─── Stripe Payment Links ───────────────────────────────────────────
|
|
// These are pre-generated checkout URLs from the Stripe Dashboard.
|
|
// Sami needs to provide his Stripe secret key so we can create these
|
|
// programmatically, or create them manually in the Stripe Dashboard.
|
|
// The product catalog (from src/billing/catalog.js):
|
|
// pro-30d → $20, 30-day license (one-time payment)
|
|
// pro-90d → $50, 90-day license (one-time payment)
|
|
// pro-180d → $70, 180-day license (one-time payment)
|
|
// pro-365d → $99, 365-day license (one-time payment)
|
|
// ─────────────────────────────────────────────────────────────────────
|
|
const STRIPE_LINKS: Record<string, string> = {
|
|
'30d': 'https://buy.stripe.com/7sY9AVgJm35P6Uo5j904800',
|
|
'90d': 'https://buy.stripe.com/bJe6oJ0Ko7m5emQ4f504801',
|
|
'180d': 'https://buy.stripe.com/4gMeVfct635P2E826X04802',
|
|
'365d': 'https://buy.stripe.com/8x228tct65dXdiM9zp04803',
|
|
};
|
|
|
|
export default function PricingPage() {
|
|
const [selectedPlan, setSelectedPlan] = useState<'30d' | '90d' | '180d' | '365d'>('365d');
|
|
|
|
const planOptions = [
|
|
{ key: '30d', label: '30 Days', price: 20, productId: 'pro-30d', perDay: '$0.67/day' },
|
|
{ key: '90d', label: '90 Days', price: 50, productId: 'pro-90d', perDay: '$0.56/day' },
|
|
{ key: '180d', label: '180 Days', price: 70, productId: 'pro-180d', perDay: '$0.39/day' },
|
|
{ key: '365d', label: '365 Days', price: 99, productId: 'pro-365d', perDay: '$0.27/day' },
|
|
] as const;
|
|
|
|
const selected = planOptions.find(p => p.key === selectedPlan)!;
|
|
|
|
const coreFeatures = [
|
|
'Dashboard & real-time service monitoring',
|
|
'76+ pre-configured app templates',
|
|
'Automatic SSL via Caddy internal CA',
|
|
'DNS automation via Technitium DNS',
|
|
'Reverse proxy management + Caddyfile-as-Code',
|
|
'AI Intent Router — natural language commands',
|
|
'MCP Server — AI assistant integration',
|
|
'Security Center — unified event pipeline',
|
|
'Service Discovery — auto-detect containers',
|
|
'Smart Defaults Wizard — guided setup',
|
|
'WebSocket real-time dashboard updates',
|
|
'TOTP 2FA + multi-user admin & invites',
|
|
'Audit logging & encrypted credential vault',
|
|
'One-click backup & disaster recovery',
|
|
'Plugin/extension system',
|
|
'JavaScript SDK + TypeScript types (39 methods)',
|
|
'Prometheus metrics export',
|
|
'i18n — 5 languages (EN/ES/FR/DE/AR)',
|
|
];
|
|
|
|
const premiumFeatures = [
|
|
'Everything in Core, plus:',
|
|
'Auto-Login SSO for deployed apps',
|
|
'Recipes — multi-container stack deployment',
|
|
'Swarm — Docker Swarm multi-node orchestration',
|
|
'Multi-Host Fleet Management — remote instance control',
|
|
'Priority support',
|
|
'One active machine per license',
|
|
'7-day grace period on expiry',
|
|
'One-time payment — no recurring billing',
|
|
];
|
|
|
|
const faqs = [
|
|
{
|
|
question: 'How does the license work?',
|
|
answer: 'You pay once and receive a license code valid for the selected duration (30, 90, 180, or 365 days). Paste it into your DashCaddy dashboard under Admin → License to unlock all premium features. No recurring billing — when it expires, you simply purchase again if you want to continue.',
|
|
},
|
|
{
|
|
question: 'What happens when my license expires?',
|
|
answer: 'Premium features gracefully deactivate after a 7-day grace period. Your services keep running — only the premium-gated features (SSO, Recipes, Swarm, Fleet Management) become unavailable. Purchase a new license at any time to re-enable them.',
|
|
},
|
|
{
|
|
question: 'Can I use DashCaddy without Premium?',
|
|
answer: 'Absolutely. The core platform is fully functional without a license — including AI commands, the Security Center, service discovery, monitoring, backup, and all 76+ app templates. Premium unlocks SSO, Recipes, Swarm orchestration, and Fleet Management for advanced multi-node setups.',
|
|
},
|
|
{
|
|
question: 'How many machines can I activate?',
|
|
answer: 'One active machine at a time per license. You can deactivate and move to a new machine when needed.',
|
|
},
|
|
{
|
|
question: 'Is my data safe?',
|
|
answer: 'DashCaddy runs entirely on your infrastructure. Your data never leaves your server. We have no access to your applications, configurations, or data.',
|
|
},
|
|
{
|
|
question: 'What payment methods do you accept?',
|
|
answer: 'We use Stripe for secure payment processing. All major credit cards are accepted. Payments are processed through Stripe\'s encrypted checkout — we never see or store your card details.',
|
|
},
|
|
];
|
|
|
|
const [expandedFaq, setExpandedFaq] = useState<number | null>(0);
|
|
|
|
return (
|
|
<div className="flex flex-col min-h-screen bg-surface-950 text-surface-50">
|
|
<Navbar />
|
|
|
|
{/* Hero */}
|
|
<section className="relative py-16 sm:py-20 lg:py-24">
|
|
<div className="absolute inset-0 -z-10">
|
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 bg-brand-500/20 rounded-full blur-3xl opacity-30 animate-pulse" />
|
|
</div>
|
|
<div className="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8 text-center">
|
|
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold mb-6">
|
|
Simple, Transparent <span className="text-brand-400">Pricing</span>
|
|
</h1>
|
|
<p className="text-xl text-surface-300 mb-8 max-w-2xl mx-auto">
|
|
The core platform is completely free — including AI commands, Security Center, and all 76+ app templates. Premium unlocks advanced orchestration with a one-time payment.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Two-column: Core vs Premium */}
|
|
<section className="relative py-12 sm:py-16 lg:py-20">
|
|
<div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
|
|
{/* Core Plan */}
|
|
<div className="relative rounded-2xl border border-surface-700/50 bg-surface-800/50 hover:border-surface-700 hover:bg-surface-800/80 transition-all">
|
|
<div className="p-8 sm:p-10">
|
|
<div className="mb-8">
|
|
<h3 className="text-2xl font-bold text-surface-50 mb-2">Core</h3>
|
|
<p className="text-surface-400 text-sm mb-6">Everything you need to deploy, manage, and secure self-hosted services — with AI built in.</p>
|
|
<div className="flex items-baseline gap-2">
|
|
<span className="text-5xl font-bold text-surface-50">Free</span>
|
|
</div>
|
|
<p className="text-surface-500 text-sm mt-2">No license required, no credit card</p>
|
|
</div>
|
|
|
|
<Link
|
|
href="/docs/installation"
|
|
className="block w-full rounded-lg border border-surface-700 bg-surface-700/50 px-6 py-3 text-center font-semibold text-surface-50 hover:border-brand-400 hover:bg-surface-700 hover:text-brand-400 transition-all"
|
|
>
|
|
Read Install Guide
|
|
</Link>
|
|
|
|
<div className="border-t border-surface-700/50 pt-8 mt-8">
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-surface-500 mb-4">Everything included — no limits</p>
|
|
<ul className="space-y-3">
|
|
{coreFeatures.map((feature, i) => (
|
|
<li key={i} className="flex items-start gap-3">
|
|
<svg className="h-5 w-5 flex-shrink-0 text-green-400 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
|
</svg>
|
|
<span className="text-surface-300 text-sm">{feature}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Premium Plan */}
|
|
<div className="relative rounded-2xl border border-brand-500/50 bg-gradient-to-br from-surface-800 to-surface-900 shadow-2xl shadow-brand-500/20">
|
|
<div className="absolute -top-4 left-1/2 -translate-x-1/2">
|
|
<span className="inline-block rounded-full bg-brand-500 px-4 py-1 text-xs font-bold uppercase tracking-wide text-white">
|
|
Premium
|
|
</span>
|
|
</div>
|
|
|
|
<div className="p-8 sm:p-10">
|
|
<div className="mb-8">
|
|
<h3 className="text-2xl font-bold text-surface-50 mb-2">Premium</h3>
|
|
<p className="text-surface-400 text-sm mb-6">Advanced orchestration, SSO, and fleet management. One-time payment — no subscription.</p>
|
|
|
|
{/* Plan selector */}
|
|
<div className="mb-4">
|
|
<div className="grid grid-cols-2 gap-2">
|
|
{planOptions.map((opt) => (
|
|
<button
|
|
key={opt.key}
|
|
onClick={() => setSelectedPlan(opt.key)}
|
|
className={`rounded-lg px-3 py-2 text-sm font-medium transition-all ${
|
|
selectedPlan === opt.key
|
|
? 'bg-brand-500 text-white'
|
|
: 'bg-surface-700/50 text-surface-400 hover:bg-surface-700 hover:text-surface-300'
|
|
}`}
|
|
>
|
|
{opt.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-baseline gap-2">
|
|
<span className="text-5xl font-bold text-surface-50">${selected.price}</span>
|
|
<span className="text-surface-400 text-lg">one-time</span>
|
|
</div>
|
|
<p className="text-brand-400 text-sm font-semibold mt-1">{selected.perDay} · {selected.productId}</p>
|
|
</div>
|
|
|
|
{/* Subscribe button — Stripe Payment Link */}
|
|
<a
|
|
href={STRIPE_LINKS[selectedPlan]}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="block w-full rounded-lg bg-brand-500 px-6 py-3 text-center font-semibold text-white hover:bg-brand-600 hover:shadow-lg hover:shadow-brand-500/30 transition-all"
|
|
>
|
|
Buy Premium License
|
|
</a>
|
|
<p className="text-center text-xs text-surface-500 mt-2">
|
|
🔒 Secure checkout via Stripe · One-time payment
|
|
</p>
|
|
|
|
<div className="border-t border-surface-700/50 pt-8 mt-8">
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-surface-500 mb-4">Everything in Core, plus</p>
|
|
<ul className="space-y-3">
|
|
{premiumFeatures.map((feature, i) => (
|
|
<li key={i} className="flex items-start gap-3">
|
|
{feature.startsWith('Everything') ? (
|
|
<span className="text-sm font-semibold text-surface-300">{feature}</span>
|
|
) : (
|
|
<>
|
|
<svg className="h-5 w-5 flex-shrink-0 text-brand-400 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
|
</svg>
|
|
<span className="text-surface-300 text-sm">{feature}</span>
|
|
</>
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* FAQ */}
|
|
<section className="relative py-16 sm:py-20 lg:py-24 bg-gradient-to-b from-surface-950 to-surface-900">
|
|
<div className="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8">
|
|
<div className="mb-12 text-center">
|
|
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4">
|
|
Frequently Asked <span className="text-brand-400">Questions</span>
|
|
</h2>
|
|
</div>
|
|
<div className="space-y-4">
|
|
{faqs.map((faq, idx) => (
|
|
<div
|
|
key={idx}
|
|
className="rounded-lg border border-surface-700/50 bg-surface-800/50 overflow-hidden transition-all hover:border-surface-700"
|
|
>
|
|
<button
|
|
onClick={() => setExpandedFaq(expandedFaq === idx ? null : idx)}
|
|
className="w-full px-6 py-4 flex items-center justify-between hover:bg-surface-800/70 transition-colors"
|
|
>
|
|
<h3 className="text-lg font-semibold text-surface-50 text-left">{faq.question}</h3>
|
|
<svg
|
|
className={`h-6 w-6 flex-shrink-0 text-brand-400 transition-transform ${expandedFaq === idx ? 'rotate-180' : ''}`}
|
|
fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor"
|
|
>
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
|
</svg>
|
|
</button>
|
|
{expandedFaq === idx && (
|
|
<div className="border-t border-surface-700/50 bg-surface-900/50 px-6 py-4">
|
|
<p className="text-surface-300 leading-relaxed">{faq.answer}</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* CTA */}
|
|
<section className="relative py-16 sm:py-20 lg:py-24 bg-surface-950">
|
|
<div className="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8 text-center">
|
|
<h2 className="text-3xl sm:text-4xl font-bold mb-6">Ready to Get Started?</h2>
|
|
<p className="text-xl text-surface-300 mb-8 max-w-2xl mx-auto">
|
|
Install DashCaddy and start deploying services in minutes. The core platform is free forever.
|
|
</p>
|
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
|
<Link
|
|
href="/docs/installation"
|
|
className="inline-flex items-center justify-center gap-2 rounded-lg bg-brand-500 px-8 py-3 text-base font-semibold text-white hover:bg-brand-600 transition-all hover:shadow-lg hover:shadow-brand-500/30"
|
|
>
|
|
Installation Guide
|
|
</Link>
|
|
<Link
|
|
href="/"
|
|
className="inline-flex items-center justify-center gap-2 rounded-lg border border-surface-700 bg-surface-800/50 px-8 py-3 text-base font-semibold text-surface-50 hover:border-brand-400 hover:bg-surface-800 transition-colors"
|
|
>
|
|
Back to Home
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<Footer />
|
|
</div>
|
|
);
|
|
}
|