fix: exercices dans panneau IA + erreur language
- Générateur d'exercices déplacé du menu ⋯ vers le panneau IA (onglet Actions > Outils de génération) - Même design que les cartes slides/diagrammes - Fix: import useLanguage supprimé de la route API (hook client en serveur) - i18n FR/EN
This commit is contained in:
@@ -3,7 +3,6 @@ import { auth } from '@/auth'
|
|||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
import { exerciseGeneratorService } from '@/lib/ai/services/exercise-generator.service'
|
import { exerciseGeneratorService } from '@/lib/ai/services/exercise-generator.service'
|
||||||
import { checkEntitlementOrThrow, QuotaExceededError, incrementUsageAsync } from '@/lib/entitlements'
|
import { checkEntitlementOrThrow, QuotaExceededError, incrementUsageAsync } from '@/lib/entitlements'
|
||||||
import { useLanguage } from '@/lib/i18n'
|
|
||||||
|
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ export function ContextualAIChat({
|
|||||||
const [translateTarget, setTranslateTarget] = useState('')
|
const [translateTarget, setTranslateTarget] = useState('')
|
||||||
|
|
||||||
// Generate slides / diagram state
|
// Generate slides / diagram state
|
||||||
const [generateLoading, setGenerateLoading] = useState<'slides' | 'diagram' | null>(null)
|
const [generateLoading, setGenerateLoading] = useState<'slides' | 'diagram' | 'exercises' | null>(null)
|
||||||
const [generateProgress, setGenerateProgress] = useState(0)
|
const [generateProgress, setGenerateProgress] = useState(0)
|
||||||
const [generateResult, setGenerateResult] = useState<GenerateResult | null>(null)
|
const [generateResult, setGenerateResult] = useState<GenerateResult | null>(null)
|
||||||
const [customLangInput, setCustomLangInput] = useState('')
|
const [customLangInput, setCustomLangInput] = useState('')
|
||||||
@@ -1228,6 +1228,54 @@ export function ContextualAIChat({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* ── Générateur d'exercices ── */}
|
||||||
|
{noteId && (
|
||||||
|
<div className="group relative p-6 rounded-2xl bg-white border border-border hover:border-brand-accent/30 transition-all duration-500 overflow-hidden">
|
||||||
|
<div className="absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity">
|
||||||
|
<PenTool size={80} className="text-brand-accent" />
|
||||||
|
</div>
|
||||||
|
<div className="relative space-y-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-2 bg-slate-50 rounded-lg text-brand-accent"><PenTool size={18} /></div>
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<h5 className="text-sm font-bold text-foreground leading-none">{t('ai.generate.exercises') || 'Générer des exercices'}</h5>
|
||||||
|
<p className="text-[9px] text-foreground/40 uppercase tracking-tight">{t('ai.generate.exercisesHint') || '5 exercices avec corrigés'}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-[10px] text-foreground/50 leading-relaxed">
|
||||||
|
{t('ai.generate.exercisesDesc') || "L'IA crée 5 exercices basés sur cette note, avec des niveaux de difficulté variés et des corrigés détaillés."}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={async () => {
|
||||||
|
if (!noteId) return
|
||||||
|
setGenerateLoading('exercises')
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/ai/generate-exercises', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ noteId, count: 5, language: t('ai.language') === 'فارسی' ? 'fa' : 'fr' }),
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
if (res.ok && data.exercises) {
|
||||||
|
toast.success(`${data.exercises.length} ${t('ai.generate.exercisesCreated') || 'exercices créés !'}`)
|
||||||
|
} else {
|
||||||
|
toast.error(data.error || 'Erreur')
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
toast.error(e.message || 'Erreur')
|
||||||
|
} finally {
|
||||||
|
setGenerateLoading(null)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={!!generateLoading}
|
||||||
|
className="w-full py-3.5 bg-brand-accent text-white rounded-xl text-[10px] font-bold flex items-center justify-center gap-2 hover:opacity-90 transition-all shadow-lg shadow-brand-accent/20 uppercase tracking-[0.2em] disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{generateLoading === 'exercises' ? <Loader2 size={14} className="animate-spin" /> : <><PenTool size={14} className="opacity-80" /> {t('ai.generate.generateExercises') || 'Générer'}</>}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* ── Personas IA ── */}
|
{/* ── Personas IA ── */}
|
||||||
<PersonasPanel noteTitle={noteTitle} noteContent={noteContent} />
|
<PersonasPanel noteTitle={noteTitle} noteContent={noteContent} />
|
||||||
|
|
||||||
|
|||||||
@@ -479,17 +479,6 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
|||||||
<Printer className="h-4 w-4 me-2" />
|
<Printer className="h-4 w-4 me-2" />
|
||||||
{t('richTextEditor.exportPdf') || 'Exporter en PDF'}
|
{t('richTextEditor.exportPdf') || 'Exporter en PDF'}
|
||||||
</DropdownMenuItem>
|
</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}>
|
<DropdownMenuItem onClick={openMarkdownImport}>
|
||||||
<FileUp className="h-4 w-4 me-2" />
|
<FileUp className="h-4 w-4 me-2" />
|
||||||
{t('richTextEditor.importMarkdown')}
|
{t('richTextEditor.importMarkdown')}
|
||||||
|
|||||||
@@ -2561,6 +2561,11 @@
|
|||||||
"generateExercises": "Generate exercises",
|
"generateExercises": "Generate exercises",
|
||||||
"exercisesLoading": "Generating exercises...",
|
"exercisesLoading": "Generating exercises...",
|
||||||
"exercisesGenerated": "exercises created!",
|
"exercisesGenerated": "exercises created!",
|
||||||
|
"aiGenerateExercises": "Generate exercises",
|
||||||
|
"aiGenerateExercisesHint": "5 exercises with answers",
|
||||||
|
"aiGenerateExercisesDesc": "AI creates 5 exercises based on this note, with varied difficulty levels and detailed answers.",
|
||||||
|
"aiGenerateExercisesCreated": "exercises created!",
|
||||||
|
"aiGenerateGenerateExercises": "Generate",
|
||||||
"wizardStudyPlanner": "Study Plan",
|
"wizardStudyPlanner": "Study Plan",
|
||||||
"wizardStudyPlannerDesc": "AI creates a revision plan based on spaced repetition.",
|
"wizardStudyPlannerDesc": "AI creates a revision plan based on spaced repetition.",
|
||||||
"wizardExamDate": "Exam date",
|
"wizardExamDate": "Exam date",
|
||||||
|
|||||||
@@ -2565,6 +2565,11 @@
|
|||||||
"generateExercises": "Générer des exercices",
|
"generateExercises": "Générer des exercices",
|
||||||
"exercisesLoading": "Génération des exercices...",
|
"exercisesLoading": "Génération des exercices...",
|
||||||
"exercisesGenerated": "exercices créés !",
|
"exercisesGenerated": "exercices créés !",
|
||||||
|
"aiGenerateExercises": "Générer des exercices",
|
||||||
|
"aiGenerateExercisesHint": "5 exercices avec corrigés",
|
||||||
|
"aiGenerateExercisesDesc": "L'IA crée 5 exercices basés sur cette note, avec des niveaux de difficulté variés et des corrigés détaillés.",
|
||||||
|
"aiGenerateExercisesCreated": "exercices créés !",
|
||||||
|
"aiGenerateGenerateExercises": "Générer",
|
||||||
"wizardStudyPlanner": "Planning de révision",
|
"wizardStudyPlanner": "Planning de révision",
|
||||||
"wizardStudyPlannerDesc": "L'IA crée un planning de révision basé sur la répétition espacée.",
|
"wizardStudyPlannerDesc": "L'IA crée un planning de révision basé sur la répétition espacée.",
|
||||||
"wizardExamDate": "Date de l'examen",
|
"wizardExamDate": "Date de l'examen",
|
||||||
|
|||||||
Reference in New Issue
Block a user