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:
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { motion, useReducedMotion } from 'motion/react'
|
||||
import { Inbox, GraduationCap, Mail, Pin, Bot, BarChart3 } from 'lucide-react'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { RevisionHeatmap } from '@/components/flashcards/revision-heatmap'
|
||||
@@ -42,14 +43,19 @@ export function DashboardWidgetShell({
|
||||
|
||||
export function DashboardInboxWidget({
|
||||
count,
|
||||
notes,
|
||||
loading,
|
||||
onOpen,
|
||||
onSelect,
|
||||
}: {
|
||||
count: number
|
||||
notes: Array<{ id: string; title: string | null; notebookId: string | null }>
|
||||
loading: boolean
|
||||
onOpen: () => void
|
||||
onSelect: (id: string, notebookId: string | null) => void
|
||||
}) {
|
||||
const { t } = useLanguage()
|
||||
const reduced = !!useReducedMotion()
|
||||
return (
|
||||
<DashboardWidgetShell
|
||||
widgetId="inbox"
|
||||
@@ -58,19 +64,42 @@ export function DashboardInboxWidget({
|
||||
compact
|
||||
>
|
||||
{loading ? (
|
||||
<div className="h-10 rounded-lg bg-stone-50 dark:bg-zinc-950/40 animate-pulse" />
|
||||
<div className="space-y-2">
|
||||
<div className="h-10 rounded-lg bg-stone-50 dark:bg-zinc-950/40 animate-pulse" />
|
||||
<div className="h-8 rounded-lg bg-stone-50 dark:bg-zinc-950/40 animate-pulse" />
|
||||
</div>
|
||||
) : notes.length === 0 ? (
|
||||
<p className="text-[11px] text-concrete italic py-1">{t('homeDashboard.inboxEmpty')}</p>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onOpen}
|
||||
className="w-full flex items-center justify-between gap-3 p-3 rounded-xl border border-border/20 hover:border-brand-accent/30 hover:bg-brand-accent/[0.03] transition-all text-start"
|
||||
>
|
||||
<div>
|
||||
<p className="text-2xl font-serif font-bold text-ink dark:text-dark-ink leading-none">{count}</p>
|
||||
<p className="text-[10px] text-concrete mt-1">{t('homeDashboard.toOrganize')}</p>
|
||||
</div>
|
||||
<span className="text-[9px] font-mono uppercase font-bold text-brand-accent">{t('homeDashboard.widgetOpen')} →</span>
|
||||
</button>
|
||||
<div className="space-y-1.5">
|
||||
{notes.map((note, idx) => (
|
||||
<motion.button
|
||||
key={note.id}
|
||||
type="button"
|
||||
onClick={() => onSelect(note.id, note.notebookId)}
|
||||
initial={reduced ? false : { opacity: 0, x: 8 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
transition={{ duration: reduced ? 0 : 0.22, delay: reduced ? 0 : Math.min(idx * 0.05, 0.15), ease: [0.16, 1, 0.3, 1] }}
|
||||
className="w-full text-start p-2.5 rounded-xl border border-border/20 hover:border-brand-accent/30 hover:bg-brand-accent/[0.03] transition-all"
|
||||
>
|
||||
<p className="text-[11px] text-ink dark:text-dark-ink truncate">
|
||||
{note.title || t('homeDashboard.untitled')}
|
||||
</p>
|
||||
</motion.button>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
onClick={onOpen}
|
||||
className="w-full flex items-center justify-between gap-2 px-1 pt-1 text-start"
|
||||
>
|
||||
<span className="text-[9px] font-mono uppercase font-bold text-concrete">
|
||||
{t('homeDashboard.inboxSeeAll', { count })}
|
||||
</span>
|
||||
<span className="text-[9px] font-mono uppercase font-bold text-brand-accent">
|
||||
{t('homeDashboard.widgetOpen')} →
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</DashboardWidgetShell>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user