feat: générateur d'exercices + planning de révision IA
- Générateur d'exercices : bouton dans menu note → IA crée 5 exercices - Niveaux variés (facile/moyen/difficile) avec emojis 🟢🟡🔴 - Corrigés détaillés dans des toggles (cliquer pour révéler) - Callout warning pour le niveau - Notes créées dans le même carnet - Planning de révision : bouton dans barre carnet → IA crée planning - Choix date d'examen - Répétition espacée (première lecture → revoir → révision globale) - Rappels automatiques ajoutés aux notes (9h le jour J) - Vue chronologique avec activités et notes par jour - Services : exercise-generator.service.ts + study-planner.service.ts - Endpoints : /api/ai/generate-exercises + /api/ai/study-plan - i18n FR/EN complet
This commit is contained in:
@@ -19,7 +19,7 @@ import { Badge } from '@/components/ui/badge'
|
||||
import {
|
||||
X, Plus, Palette, Image as ImageIcon, Bell, Eye, Link as LinkIcon, Sparkles,
|
||||
Maximize2, Copy, ArrowLeft, ChevronRight, PanelRight, Check, Loader2, Save, MoreHorizontal,
|
||||
Trash2, LogOut, Wand2, Share2, Wind, Paperclip, GraduationCap, FileDown, FileUp, Mic, MicOff, Printer
|
||||
Trash2, LogOut, Wand2, Share2, Wind, Paperclip, GraduationCap, FileDown, FileUp, Mic, MicOff, Printer, PenTool, Loader2 as Loader2Icon
|
||||
} from 'lucide-react'
|
||||
import { FlashcardGenerateDialog } from '@/components/flashcards/flashcard-generate-dialog'
|
||||
import { NoteShareDialog } from './note-share-dialog'
|
||||
@@ -235,6 +235,29 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
input.click()
|
||||
}
|
||||
|
||||
const [generatingExercises, setGeneratingExercises] = useState(false)
|
||||
const handleGenerateExercises = async () => {
|
||||
if (generatingExercises) return
|
||||
setGeneratingExercises(true)
|
||||
try {
|
||||
const res = await fetch('/api/ai/generate-exercises', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ noteId: note.id, count: 5, language }),
|
||||
})
|
||||
const data = await res.json()
|
||||
if (!res.ok) {
|
||||
toast.error(data.errorKey === 'ai.featureLocked' ? (t('ai.featureLocked') || 'Plan requis') : (data.error || 'Erreur'))
|
||||
} else {
|
||||
toast.success(t('richTextEditor.exercisesGenerated') || `${data.exercises?.length || 0} exercices créés !`)
|
||||
}
|
||||
} catch (e: any) {
|
||||
toast.error(e.message || 'Erreur')
|
||||
} finally {
|
||||
setGeneratingExercises(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleConvertToRichtext = async () => {
|
||||
if (isConverting || !state.content.trim()) return
|
||||
setIsConverting(true)
|
||||
@@ -456,6 +479,17 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
<Printer className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.exportPdf') || 'Exporter en PDF'}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={handleGenerateExercises} disabled={generatingExercises}>
|
||||
{generatingExercises
|
||||
? <Loader2Icon className="h-4 w-4 me-2 animate-spin" />
|
||||
: <PenTool className="h-4 w-4 me-2 text-brand-accent" />
|
||||
}
|
||||
{generatingExercises
|
||||
? (t('richTextEditor.exercisesLoading') || 'Génération...')
|
||||
: (t('richTextEditor.generateExercises') || 'Générer des exercices')
|
||||
}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={openMarkdownImport}>
|
||||
<FileUp className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.importMarkdown')}
|
||||
|
||||
Reference in New Issue
Block a user