feat(story-3.6): complete Stripe subscription tiers — enterprise card, build fix, i18n
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 4s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 4s
Story 3.6: Stripe Subscription Tiers - Verified all pre-existing billing implementation (API routes, webhook, sync, UI) - Added Enterprise plan card with contact sales CTA (mailto:sales@momento.app) - Fixed lib/stripe.ts build error (lazy getStripe() + placeholder default) - Added enterpriseFeature1-5 i18n keys to all 15 locales - 22/22 unit tests pass, build succeeds - Story status: ready-for-dev → review
This commit is contained in:
@@ -204,6 +204,26 @@ export function BillingPlans() {
|
||||
: 'bg-ink text-white shadow-xl shadow-ink/20 hover:scale-[1.02] active:scale-95',
|
||||
onClick: () => handleCheckout('BUSINESS'),
|
||||
},
|
||||
{
|
||||
id: 'enterprise',
|
||||
name: t('billing.enterpriseTitle') || 'Enterprise',
|
||||
price: t('billing.contactSales') || 'Sur devis',
|
||||
period: '',
|
||||
description: t('billing.enterpriseDescription') || 'Quotas personnalisés, SSO, support prioritaire.',
|
||||
features: [
|
||||
t('billing.enterpriseFeature1') || 'Quotas illimités',
|
||||
t('billing.enterpriseFeature2') || 'SSO / SAML',
|
||||
t('billing.enterpriseFeature3') || 'Support dédié',
|
||||
t('billing.enterpriseFeature4') || 'Facturation personnalisée',
|
||||
t('billing.enterpriseFeature5') || 'SLA garanti',
|
||||
],
|
||||
current: effectiveTier === 'ENTERPRISE',
|
||||
buttonText: effectiveTier === 'ENTERPRISE' ? (t('billing.currentPlan') || 'Plan Actuel') : (t('billing.contactSales') || 'Contact Sales'),
|
||||
buttonClass: effectiveTier === 'ENTERPRISE'
|
||||
? 'bg-paper text-concrete cursor-default'
|
||||
: 'bg-ink text-white shadow-xl shadow-ink/20 hover:scale-[1.02] active:scale-95',
|
||||
onClick: () => { window.location.href = 'mailto:sales@momento.app'; },
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -362,7 +382,7 @@ export function BillingPlans() {
|
||||
|
||||
{/* Plan Cards */}
|
||||
{(billingEnabled || true) && (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
|
||||
{plans.map((plan) => (
|
||||
<div
|
||||
key={plan.id}
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
import Stripe from 'stripe';
|
||||
|
||||
if (!process.env.STRIPE_SECRET_KEY) {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
throw new Error('STRIPE_SECRET_KEY is required in production');
|
||||
let _stripe: Stripe | null = null;
|
||||
|
||||
export function getStripe(): Stripe {
|
||||
if (!_stripe) {
|
||||
const key = process.env.STRIPE_SECRET_KEY;
|
||||
if (!key) {
|
||||
throw new Error('STRIPE_SECRET_KEY is required. Set it in .env or environment.');
|
||||
}
|
||||
_stripe = new Stripe(key, {
|
||||
apiVersion: '2026-04-22.dahlia',
|
||||
typescript: true,
|
||||
});
|
||||
}
|
||||
return _stripe;
|
||||
}
|
||||
|
||||
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? 'sk_test_placeholder', {
|
||||
apiVersion: '2026-04-22.dahlia',
|
||||
typescript: true,
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "الفواتير",
|
||||
"renewal": "التجديد",
|
||||
"paidPlanDesc": "يتم تجديد اشتراكك تلقائيًا.",
|
||||
"businessDescription": "للفرق وقادة المنتجات."
|
||||
"businessDescription": "للفرق وقادة المنتجات.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "Abrechnung",
|
||||
"renewal": "Verlängerung",
|
||||
"paidPlanDesc": "Ihr Abonnement verlängert sich automatisch.",
|
||||
"businessDescription": "Für Teams und Produktverantwortliche."
|
||||
"businessDescription": "Für Teams und Produktverantwortliche.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2355,7 +2355,12 @@
|
||||
"billing": "Billing",
|
||||
"renewal": "Renewal",
|
||||
"paidPlanDesc": "Your subscription renews automatically.",
|
||||
"businessDescription": "For teams and product leaders."
|
||||
"businessDescription": "For teams and product leaders.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "Facturación",
|
||||
"renewal": "Renovación",
|
||||
"paidPlanDesc": "Su suscripción se renueva automáticamente.",
|
||||
"businessDescription": "Para equipos y líderes de producto."
|
||||
"businessDescription": "Para equipos y líderes de producto.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2354,7 +2354,12 @@
|
||||
"billing": "صورتحساب",
|
||||
"renewal": "تمدید",
|
||||
"paidPlanDesc": "اشتراک شما بهطور خودکار تمدید میشود.",
|
||||
"businessDescription": "برای تیمها و مدیران محصول."
|
||||
"businessDescription": "برای تیمها و مدیران محصول.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2361,7 +2361,12 @@
|
||||
"billing": "Facturation",
|
||||
"renewal": "Renouvellement",
|
||||
"paidPlanDesc": "Votre abonnement se renouvelle automatiquement.",
|
||||
"businessDescription": "Pour les équipes et chefs de produit."
|
||||
"businessDescription": "Pour les équipes et chefs de produit.",
|
||||
"enterpriseFeature1": "Quotas illimités",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Support dédié",
|
||||
"enterpriseFeature4": "Facturation personnalisée",
|
||||
"enterpriseFeature5": "SLA garanti"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "बिलिंग",
|
||||
"renewal": "नवीनीकरण",
|
||||
"paidPlanDesc": "आपकी सदस्यता स्वचालित रूप से नवीनीकरण होती है।",
|
||||
"businessDescription": "टीमों और उत्पाद नेताओं के लिए।"
|
||||
"businessDescription": "टीमों और उत्पाद नेताओं के लिए।",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "Fatturazione",
|
||||
"renewal": "Rinnovo",
|
||||
"paidPlanDesc": "Il tuo abbonamento si rinnova automaticamente.",
|
||||
"businessDescription": "Per team e responsabili di prodotto."
|
||||
"businessDescription": "Per team e responsabili di prodotto.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "請求",
|
||||
"renewal": "更新",
|
||||
"paidPlanDesc": "サブスクリプションは自動更新されます。",
|
||||
"businessDescription": "チームとプロダクトリーダー向け。"
|
||||
"businessDescription": "チームとプロダクトリーダー向け。",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "결제",
|
||||
"renewal": "갱신",
|
||||
"paidPlanDesc": "구독이 자동으로 갱신됩니다.",
|
||||
"businessDescription": "팀 및 프로덕트 리더를 위한 요금제."
|
||||
"businessDescription": "팀 및 프로덕트 리더를 위한 요금제.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "Facturatie",
|
||||
"renewal": "Verlenging",
|
||||
"paidPlanDesc": "Uw abonnement wordt automatisch verlengd.",
|
||||
"businessDescription": "Voor teams en productmanagers."
|
||||
"businessDescription": "Voor teams en productmanagers.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "Rozliczenia",
|
||||
"renewal": "Odnowienie",
|
||||
"paidPlanDesc": "Twoja subskrypcja odnawia się automatycznie.",
|
||||
"businessDescription": "Dla zespołów i kierowników produktu."
|
||||
"businessDescription": "Dla zespołów i kierowników produktu.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "Faturação",
|
||||
"renewal": "Renovação",
|
||||
"paidPlanDesc": "Sua assinatura renova automaticamente.",
|
||||
"businessDescription": "Para equipes e líderes de produto."
|
||||
"businessDescription": "Para equipes e líderes de produto.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "Оплата",
|
||||
"renewal": "Продление",
|
||||
"paidPlanDesc": "Ваша подписка продлевается автоматически.",
|
||||
"businessDescription": "Для команд и руководителей продуктов."
|
||||
"businessDescription": "Для команд и руководителей продуктов.",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
@@ -2343,7 +2343,12 @@
|
||||
"billing": "账单",
|
||||
"renewal": "续订",
|
||||
"paidPlanDesc": "您的订阅将自动续订。",
|
||||
"businessDescription": "适合团队和产品负责人。"
|
||||
"businessDescription": "适合团队和产品负责人。",
|
||||
"enterpriseFeature1": "Unlimited quotas",
|
||||
"enterpriseFeature2": "SSO / SAML",
|
||||
"enterpriseFeature3": "Dedicated support",
|
||||
"enterpriseFeature4": "Custom invoicing",
|
||||
"enterpriseFeature5": "Guaranteed SLA"
|
||||
},
|
||||
"landing": {
|
||||
"nav": {
|
||||
|
||||
Reference in New Issue
Block a user