fix: Memory Echo sans vol de scroll, badge IA sidebar, wizard langue
- Ne plus auto-scroller vers Memory Echo : pastille bas de page + reset scroll au titre - Badges notes/carnets générés par l’IA dans la sidebar - Wizard : langue du contenu = langue de la requête ; refresh carnet après création - Voix : erreurs not-allowed/no-speech moins bruyantes
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useState, useRef } from 'react'
|
||||
import { GraduationCap, BookOpen, Wrench, Sparkles, Loader2, X, ArrowRight, ArrowLeft, Check, FileText } from 'lucide-react'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { toast } from 'sonner'
|
||||
import { markAiCreatedNotebook } from '@/lib/ai-created-highlight'
|
||||
|
||||
type WizardProfile = 'student' | 'teacher' | 'engineer'
|
||||
|
||||
@@ -42,7 +43,7 @@ const PROFILES: ProfileOption[] = [
|
||||
|
||||
const LEVELS = ['wizard.levelBeginner', 'wizard.levelIntermediate', 'wizard.levelAdvanced', 'wizard.levelExpert']
|
||||
|
||||
export function AiNotebookWizard({ onClose, onComplete }: { onClose: () => void; onComplete: (notebookId: string) => void }) {
|
||||
export function AiNotebookWizard({ onClose, onComplete }: { onClose: () => void; onComplete: (notebookId: string) => void | Promise<void> }) {
|
||||
const { t, language } = useLanguage()
|
||||
const [step, setStep] = useState<0 | 1 | 2>(0)
|
||||
const [profile, setProfile] = useState<WizardProfile | null>(null)
|
||||
@@ -52,6 +53,25 @@ export function AiNotebookWizard({ onClose, onComplete }: { onClose: () => void;
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [progressMsg, setProgressMsg] = useState('')
|
||||
const [success, setSuccess] = useState<{ notebookId: string; notebookName: string; noteTitles: string[] } | null>(null)
|
||||
const [opening, setOpening] = useState(false)
|
||||
const completedRef = useRef(false)
|
||||
|
||||
const finishAndOpen = async (notebookId: string, notebookName: string) => {
|
||||
if (completedRef.current) return
|
||||
completedRef.current = true
|
||||
setOpening(true)
|
||||
try {
|
||||
markAiCreatedNotebook(notebookId)
|
||||
const toastMsg = (t('wizard.createdToast') || 'Carnet « {name} » prêt — notes IA disponibles')
|
||||
.replace('{name}', notebookName)
|
||||
toast.success(toastMsg)
|
||||
await onComplete(notebookId)
|
||||
} catch (e: any) {
|
||||
completedRef.current = false
|
||||
setOpening(false)
|
||||
toast.error(e?.message || t('general.error') || 'Erreur')
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!profile || !topic.trim()) return
|
||||
@@ -68,7 +88,6 @@ export function AiNotebookWizard({ onClose, onComplete }: { onClose: () => void;
|
||||
level: t(LEVELS[level]),
|
||||
count,
|
||||
language,
|
||||
// Server generates a short title from the topic; do not force raw prompt as name
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -87,14 +106,16 @@ export function AiNotebookWizard({ onClose, onComplete }: { onClose: () => void;
|
||||
return
|
||||
}
|
||||
|
||||
setProgressMsg(t('wizard.progressCreating') || 'Création du carnet et des notes...')
|
||||
|
||||
const notebookId = data.notebookId as string
|
||||
const notebookName = (data.notebookName || topic) as string
|
||||
setSuccess({
|
||||
notebookId: data.notebookId,
|
||||
notebookName: data.notebookName || topic,
|
||||
notebookId,
|
||||
notebookName,
|
||||
noteTitles: data.noteTitles || [],
|
||||
})
|
||||
setLoading(false)
|
||||
// Ouvre tout de suite : refresh sidebar + navigation (plus besoin de F5)
|
||||
void finishAndOpen(notebookId, notebookName)
|
||||
} catch (e: any) {
|
||||
toast.error(e.message || 'Erreur')
|
||||
setLoading(false)
|
||||
@@ -159,12 +180,19 @@ export function AiNotebookWizard({ onClose, onComplete }: { onClose: () => void;
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => onComplete(success.notebookId)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 text-sm rounded-lg bg-brand-accent text-white hover:bg-brand-accent/90 transition-colors font-medium"
|
||||
type="button"
|
||||
disabled={opening}
|
||||
onClick={() => void finishAndOpen(success.notebookId, success.notebookName)}
|
||||
className="flex items-center gap-2 px-5 py-2.5 text-sm rounded-lg bg-brand-accent text-white hover:bg-brand-accent/90 transition-colors font-medium disabled:opacity-60"
|
||||
>
|
||||
<Sparkles className="h-4 w-4" />
|
||||
{t('wizard.openNotebook') || 'Ouvrir le carnet'}
|
||||
{opening ? <Loader2 className="h-4 w-4 animate-spin" /> : <Sparkles className="h-4 w-4" />}
|
||||
{opening
|
||||
? (t('wizard.openingNotebook') || 'Ouverture…')
|
||||
: (t('wizard.openNotebook') || 'Ouvrir le carnet')}
|
||||
</button>
|
||||
<p className="text-[11px] text-muted-foreground text-center max-w-sm">
|
||||
{t('wizard.autoOpenHint') || 'Ouverture automatique du carnet et mise à jour de la barre latérale…'}
|
||||
</p>
|
||||
</div>
|
||||
) : loading ? (
|
||||
<div className="flex flex-col items-center justify-center py-16 gap-4">
|
||||
|
||||
Reference in New Issue
Block a user