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:
97
memento-note/app/(auth)/verify-email/page.tsx
Normal file
97
memento-note/app/(auth)/verify-email/page.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
'use client'
|
||||
|
||||
import { Suspense, useEffect, useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { CheckCircle2, AlertCircle, Sparkles } from 'lucide-react'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { confirmEmail } from '@/app/actions/auth-verify'
|
||||
|
||||
function VerifyEmailContent() {
|
||||
const { t } = useLanguage()
|
||||
const searchParams = useSearchParams()
|
||||
const token = searchParams.get('token')
|
||||
const [status, setStatus] = useState<'loading' | 'ok' | 'invalid' | 'expired'>('loading')
|
||||
|
||||
useEffect(() => {
|
||||
if (!token) {
|
||||
setStatus('invalid')
|
||||
return
|
||||
}
|
||||
let cancelled = false
|
||||
;(async () => {
|
||||
const result = await confirmEmail(token)
|
||||
if (cancelled) return
|
||||
if (result.success) setStatus('ok')
|
||||
else setStatus(result.error === 'expired' ? 'expired' : 'invalid')
|
||||
})()
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [token])
|
||||
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<div className="bg-white dark:bg-[var(--background)]/50 border border-[var(--border)] p-8 md:p-10 rounded-[48px] shadow-2xl text-center space-y-4">
|
||||
<Sparkles size={28} className="mx-auto animate-spin text-[var(--color-brand-accent)]" />
|
||||
<p className="text-sm text-[var(--muted-foreground)]">{t('auth.verifyLoading')}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (status === 'ok') {
|
||||
return (
|
||||
<div className="bg-white dark:bg-[var(--background)]/50 border border-[var(--border)] p-8 md:p-10 rounded-[48px] shadow-2xl text-center space-y-6">
|
||||
<div className="w-14 h-14 mx-auto rounded-2xl bg-emerald-500/10 flex items-center justify-center">
|
||||
<CheckCircle2 size={28} className="text-emerald-600" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<h1 className="text-2xl font-serif font-bold">{t('auth.verifySuccessTitle')}</h1>
|
||||
<p className="text-sm text-[var(--muted-foreground)]">{t('auth.verifySuccessDescription')}</p>
|
||||
</div>
|
||||
<Link href="/login?verified=1" className="block">
|
||||
<button
|
||||
type="button"
|
||||
className="w-full bg-[var(--foreground)] text-[var(--background)] py-4 rounded-2xl font-bold uppercase tracking-[0.2em] text-[10px] transition-all hover:shadow-xl active:scale-[0.98]"
|
||||
>
|
||||
{t('auth.signIn')}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-[var(--background)]/50 border border-[var(--border)] p-8 md:p-10 rounded-[48px] shadow-2xl text-center space-y-6">
|
||||
<div className="w-14 h-14 mx-auto rounded-2xl bg-red-500/10 flex items-center justify-center">
|
||||
<AlertCircle size={28} className="text-red-500" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<h1 className="text-2xl font-serif font-bold">
|
||||
{status === 'expired' ? t('auth.verifyExpiredTitle') : t('auth.verifyInvalidTitle')}
|
||||
</h1>
|
||||
<p className="text-sm text-[var(--muted-foreground)]">
|
||||
{status === 'expired'
|
||||
? t('auth.verifyExpiredDescription')
|
||||
: t('auth.verifyInvalidDescription')}
|
||||
</p>
|
||||
</div>
|
||||
<Link href="/check-email" className="block">
|
||||
<button
|
||||
type="button"
|
||||
className="w-full bg-[var(--foreground)] text-[var(--background)] py-4 rounded-2xl font-bold uppercase tracking-[0.2em] text-[10px] transition-all hover:shadow-xl active:scale-[0.98]"
|
||||
>
|
||||
{t('auth.resendVerification')}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function VerifyEmailPage() {
|
||||
return (
|
||||
<Suspense fallback={<div className="p-10 text-center text-sm text-muted-foreground">…</div>}>
|
||||
<VerifyEmailContent />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user