Fix pricing page: one-time payments by days (not subscriptions)
Pricing model from catalog.js: 0/30d, 0/90d, 0/180d, 9/365d All one-time payments, not recurring subscriptions. Updated plan selector, FAQ, and button labels accordingly.
This commit is contained in:
+29
-31
@@ -7,25 +7,29 @@ import Footer from '@/components/Footer';
|
||||
|
||||
// ─── Stripe Payment Links ───────────────────────────────────────────
|
||||
// These are pre-generated checkout URLs from the Stripe Dashboard.
|
||||
// Replace these placeholders with real Payment Link URLs from:
|
||||
// https://dashboard.stripe.com/payment-links
|
||||
// Each link should point to the corresponding Stripe Product/Price.
|
||||
// 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> = {
|
||||
monthly: 'https://buy.stripe.com/REPLACE_MONTHLY_LINK',
|
||||
quarterly: 'https://buy.stripe.com/REPLACE_QUARTERLY_LINK',
|
||||
semiannual: 'https://buy.stripe.com/REPLACE_SEMIANNUAL_LINK',
|
||||
annual: 'https://buy.stripe.com/REPLACE_ANNUAL_LINK',
|
||||
'30d': 'https://buy.stripe.com/REPLACE_30D_LINK',
|
||||
'90d': 'https://buy.stripe.com/REPLACE_90D_LINK',
|
||||
'180d': 'https://buy.stripe.com/REPLACE_180D_LINK',
|
||||
'365d': 'https://buy.stripe.com/REPLACE_365D_LINK',
|
||||
};
|
||||
|
||||
export default function PricingPage() {
|
||||
const [selectedPlan, setSelectedPlan] = useState<'monthly' | 'quarterly' | 'semiannual' | 'annual'>('annual');
|
||||
const [selectedPlan, setSelectedPlan] = useState<'30d' | '90d' | '180d' | '365d'>('365d');
|
||||
|
||||
const planOptions = [
|
||||
{ key: 'monthly', label: '1 Month', price: 25, period: '/mo', perMonth: undefined },
|
||||
{ key: 'quarterly', label: '3 Months', price: 50, period: '/3mo', perMonth: '$16.67/mo' },
|
||||
{ key: 'semiannual', label: '6 Months', price: 65, period: '/6mo', perMonth: '$10.83/mo' },
|
||||
{ key: 'annual', label: '12 Months', price: 99, period: '/yr', perMonth: '$8.25/mo' },
|
||||
{ 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)!;
|
||||
@@ -60,13 +64,17 @@ export default function PricingPage() {
|
||||
'Priority support',
|
||||
'One active machine per license',
|
||||
'7-day grace period on expiry',
|
||||
'Cancel at period end, no lock-in',
|
||||
'One-time payment — no recurring billing',
|
||||
];
|
||||
|
||||
const faqs = [
|
||||
{
|
||||
question: 'What happens when my subscription ends?',
|
||||
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. Resubscribe at any time to re-enable them.',
|
||||
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?',
|
||||
@@ -76,18 +84,10 @@ export default function PricingPage() {
|
||||
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 there a free trial?',
|
||||
answer: 'Not currently. The core platform is available without a license, so you can fully evaluate DashCaddy before purchasing Premium.',
|
||||
},
|
||||
{
|
||||
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: 'How does license validation work?',
|
||||
answer: 'DashCaddy validates licenses through an external license server. The app checks your subscription status and activates or deactivates premium features accordingly.',
|
||||
},
|
||||
{
|
||||
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.',
|
||||
@@ -110,7 +110,7 @@ export default function PricingPage() {
|
||||
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 when you need it.
|
||||
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>
|
||||
@@ -166,7 +166,7 @@ export default function PricingPage() {
|
||||
<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 for power users and production.</p>
|
||||
<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">
|
||||
@@ -189,11 +189,9 @@ export default function PricingPage() {
|
||||
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-5xl font-bold text-surface-50">${selected.price}</span>
|
||||
<span className="text-surface-400">{selected.period}</span>
|
||||
<span className="text-surface-400 text-lg">one-time</span>
|
||||
</div>
|
||||
{selected.perMonth && (
|
||||
<p className="text-brand-400 text-sm font-semibold mt-1">{selected.perMonth}</p>
|
||||
)}
|
||||
<p className="text-brand-400 text-sm font-semibold mt-1">{selected.perDay} · {selected.productId}</p>
|
||||
</div>
|
||||
|
||||
{/* Subscribe button — Stripe Payment Link */}
|
||||
@@ -203,10 +201,10 @@ export default function PricingPage() {
|
||||
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"
|
||||
>
|
||||
Subscribe to Premium
|
||||
Buy Premium License
|
||||
</a>
|
||||
<p className="text-center text-xs text-surface-500 mt-2">
|
||||
🔒 Secure checkout via Stripe
|
||||
🔒 Secure checkout via Stripe · One-time payment
|
||||
</p>
|
||||
|
||||
<div className="border-t border-surface-700/50 pt-8 mt-8">
|
||||
|
||||
Reference in New Issue
Block a user