'use client' import { useState, useCallback, useEffect } from 'react' import { createPortal } from 'react-dom' import { GraduationCap, Loader2, Sparkles, X } from 'lucide-react' import { useLanguage } from '@/lib/i18n' import { useAiConsent } from '@/components/legal/ai-consent-provider' import { toast } from 'sonner' import { cn } from '@/lib/utils' export type FlashcardStyle = 'qa' | 'cloze' | 'concept' export interface PreviewCard { front: string back: string type: FlashcardStyle } interface FlashcardGenerateDialogProps { open: boolean onClose: () => void noteId: string noteTitle: string onSaved?: (deckId: string) => void } export function FlashcardGenerateDialog({ open, onClose, noteId, noteTitle, onSaved, }: FlashcardGenerateDialogProps) { const { t } = useLanguage() const { requestAiConsent } = useAiConsent() const [count, setCount] = useState(10) const [style, setStyle] = useState('qa') const [loading, setLoading] = useState(false) const [saving, setSaving] = useState(false) const [cards, setCards] = useState(null) const [mounted, setMounted] = useState(false) useEffect(() => { setMounted(true) }, []) useEffect(() => { if (!open) return const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', onKey) return () => document.removeEventListener('keydown', onKey) }, [open, onClose]) const handleGenerate = useCallback(async () => { if (!(await requestAiConsent())) return setLoading(true) try { const res = await fetch('/api/flashcards/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ noteId, count, style }), }) const data = await res.json() if (!res.ok) { if (data.errorKey) { toast.error(t(data.errorKey) || data.error) } else { toast.error(data.error || t('flashcards.generateFailed')) } return } setCards(data.cards || []) } catch { toast.error(t('flashcards.generateFailed')) } finally { setLoading(false) } }, [count, noteId, requestAiConsent, style, t]) const handleSave = useCallback(async () => { if (!cards?.length) return setSaving(true) try { const res = await fetch('/api/flashcards/save', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ noteId, cards }), }) const data = await res.json() if (!res.ok) { toast.error( (data.errorKey ? t(data.errorKey) : null) || data.error || t('flashcards.saveFailed'), ) return } toast.success(t('flashcards.savedCount', { count: data.savedCount })) onSaved?.(data.deckId) onClose() setCards(null) } catch { toast.error(t('flashcards.saveFailed')) } finally { setSaving(false) } }, [cards, noteId, onClose, onSaved, t]) const updateCard = (index: number, field: 'front' | 'back', value: string) => { setCards((prev) => { if (!prev) return prev const next = [...prev] next[index] = { ...next[index], [field]: value } return next }) } if (!open || !mounted) return null return createPortal(
e.stopPropagation()} >

{t('flashcards.generateTitle')}

{noteTitle}

{!cards ? ( <>
setCount(Number(e.target.value))} className="w-full accent-brand-accent" />
{(['qa', 'cloze', 'concept'] as const).map((s) => ( ))}
) : (

{t('flashcards.previewHint')}

{cards.map((card, i) => (
updateCard(i, 'front', e.target.value)} className="w-full text-sm font-medium bg-transparent border-b border-border/40 pb-1 outline-none" placeholder={t('flashcards.frontPlaceholder')} />