feat: dashboard Second Brain, essai 7 jours et vérification e-mail
Rendre le dashboard actionnable (inbox, peek, carte mentale), aligner la facturation sur l’essai 7 jours, et bloquer le login e-mail tant que l’adresse n’est pas confirmée. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,18 +4,38 @@ import { motion } from 'motion/react'
|
||||
import { Shield } from 'lucide-react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { SUBSCRIPTION_TRIAL_DAYS } from '@/lib/billing/trial-constants'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function PricingPage() {
|
||||
const { t } = useLanguage()
|
||||
const router = useRouter()
|
||||
const [billingInterval, setBillingInterval] = useState<'monthly' | 'annual'>('monthly')
|
||||
const trialDays = SUBSCRIPTION_TRIAL_DAYS
|
||||
|
||||
const PLANS = [
|
||||
{ key: 'basic', popular: false, price: t('landing.pricing.basicPrice'), period: '' },
|
||||
{ key: 'pro', popular: true, price: billingInterval === 'monthly' ? '9,90€' : '7,90€', period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual') },
|
||||
{ key: 'business', popular: false, price: billingInterval === 'monthly' ? '29,90€' : '23,90€', period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual') },
|
||||
{ key: 'enterprise', popular: false, price: billingInterval === 'monthly' ? '49,90€' : '39,90€', period: billingInterval === 'monthly' ? t('landing.pricing.perUser') : t('landing.pricing.perUserAnnual') },
|
||||
{ key: 'basic', popular: false, hasTrial: false, price: t('landing.pricing.basicPrice'), period: '' },
|
||||
{
|
||||
key: 'pro',
|
||||
popular: true,
|
||||
hasTrial: true,
|
||||
price: billingInterval === 'monthly' ? t('landing.pricing.proMonthly') : t('landing.pricing.proAnnualMonthly'),
|
||||
period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual'),
|
||||
},
|
||||
{
|
||||
key: 'business',
|
||||
popular: false,
|
||||
hasTrial: true,
|
||||
price: billingInterval === 'monthly' ? t('landing.pricing.businessMonthly') : t('landing.pricing.businessAnnualMonthly'),
|
||||
period: billingInterval === 'monthly' ? t('landing.pricing.perMonth') : t('landing.pricing.perMonthAnnual'),
|
||||
},
|
||||
{
|
||||
key: 'enterprise',
|
||||
popular: false,
|
||||
hasTrial: false,
|
||||
price: t('landing.pricing.enterprisePrice'),
|
||||
period: '',
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
@@ -42,7 +62,9 @@ export default function PricingPage() {
|
||||
)}
|
||||
</button>
|
||||
<div className="absolute -top-6 left-1/2 -translate-x-1/2 whitespace-nowrap">
|
||||
<span className="text-[9px] font-bold text-ochre uppercase tracking-widest italic animate-pulse">(-20%)</span>
|
||||
<span className="text-[9px] font-bold text-ochre uppercase tracking-widest italic animate-pulse">
|
||||
{t('landing.pricing.savePercent')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -62,9 +84,22 @@ export default function PricingPage() {
|
||||
<span className="text-4xl font-serif font-medium">{plan.price}</span>
|
||||
{plan.period && <span className="text-xs opacity-60">{plan.period}</span>}
|
||||
</div>
|
||||
{plan.hasTrial && (
|
||||
<p className={`text-[11px] font-semibold mb-3 ${plan.popular ? 'text-ochre' : 'text-brand-accent'}`}>
|
||||
{t('landing.pricing.trialBadge', { days: trialDays })}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-sm font-light leading-relaxed opacity-80">{t(`landing.pricing.${plan.key}.desc`)}</p>
|
||||
</div>
|
||||
<div className="flex-1 space-y-4 mb-10">
|
||||
{plan.hasTrial && (
|
||||
<div className="flex items-start gap-3">
|
||||
<div className={`mt-1 rounded-full p-0.5 ${plan.popular ? 'bg-ochre text-ink' : 'bg-brand-accent/10 text-brand-accent'}`}>
|
||||
<Shield size={10} fill="currentColor" />
|
||||
</div>
|
||||
<span className="text-xs font-medium">{t('landing.pricing.trialFeature', { days: trialDays })}</span>
|
||||
</div>
|
||||
)}
|
||||
{[0, 1, 2, 3, 4, 5].map(j => {
|
||||
const feat = t(`landing.pricing.${plan.key}.feature${j}`)
|
||||
if (!feat || feat === `landing.pricing.${plan.key}.feature${j}`) return null
|
||||
@@ -82,7 +117,9 @@ export default function PricingPage() {
|
||||
onClick={() => router.push('/register')}
|
||||
className={`w-full py-4 rounded-2xl text-xs font-bold uppercase tracking-widest transition-all ${plan.popular ? 'bg-ochre text-ink hover:opacity-90' : 'bg-ink text-paper hover:bg-ink/90'}`}
|
||||
>
|
||||
{t(`landing.pricing.${plan.key}.cta`)}
|
||||
{plan.hasTrial
|
||||
? t('landing.pricing.trialCta', { days: trialDays })
|
||||
: t(`landing.pricing.${plan.key}.cta`)}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user