QuizFlash / src /components /article /ArticleGenerationModal.tsx
Shih-hungg's picture
Rearrange article parameters
fe844e6
'use client';
import { useState, useEffect } from 'react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogFooter,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { ScrollArea } from '@/components/ui/scroll-area';
import { CheckboxField } from '@/components/ui/checkbox-field';
import { Loader2 } from 'lucide-react';
interface ArticleGenerationModalProps {
isOpen: boolean;
onClose: () => void;
onGenerate: (params: ArticleGenerationParams) => void;
isGenerating: boolean;
}
export interface ArticleGenerationParams {
publisher: string[];
grade: string[];
unit: string[];
textbookVocab: string;
additionalVocab: string;
grammar: string[];
topic: string[];
inputArticle: string;
}
// Options based on the Python entry_form.py
const PUBLISHER_OPTIONS = [
'康軒', '南一', '翰林'
];
const GRADE_OPTIONS = [
'七年級上學期', '七年級下學期',
'八年級上學期', '八年級下學期',
'九年級上學期', '九年級下學期'
];
const UNIT_OPTIONS = [
'第一課', '第二課', '第三課', '第四課', '第五課', '第六課'
];
const GRAMMAR_OPTIONS = [
'名詞', '動詞', '形容詞', '副詞', '介系詞', '連接詞', '助詞'
];
const TOPIC_OPTIONS = [
'家庭', '學校', '運動', '食物', '動物', '旅遊', '科技', '環境', '友誼', '夢想'
];
export function ArticleGenerationModal({
isOpen,
onClose,
onGenerate,
isGenerating
}: ArticleGenerationModalProps) {
const [formData, setFormData] = useState<ArticleGenerationParams>({
publisher: [],
grade: [],
unit: [],
textbookVocab: '',
additionalVocab: '',
grammar: [],
topic: [],
inputArticle: ''
});
// Reset form when modal opens
useEffect(() => {
if (isOpen) {
setFormData({
publisher: [],
grade: [],
unit: [],
textbookVocab: '',
additionalVocab: '',
grammar: [],
topic: [],
inputArticle: ''
});
}
}, [isOpen]);
// Update textbook vocabulary when selections change
useEffect(() => {
if (formData.grade.length > 0 && formData.unit.length > 0 && formData.publisher.length > 0) {
// Mock vocabulary update - in real implementation this would call an API
const mockVocab = "apple, book, computer, desk, elephant, friend, green, happy, important, jump";
setFormData(prev => ({ ...prev, textbookVocab: mockVocab }));
} else {
setFormData(prev => ({ ...prev, textbookVocab: '' }));
}
}, [formData.grade, formData.unit, formData.publisher]);
const handleCheckboxChange = (field: keyof ArticleGenerationParams, value: string) => {
setFormData(prev => {
const currentArray = prev[field] as string[];
const newArray = currentArray.includes(value)
? currentArray.filter(item => item !== value)
: [...currentArray, value];
return { ...prev, [field]: newArray };
});
};
const handleTextChange = (field: keyof ArticleGenerationParams, value: string) => {
setFormData(prev => ({ ...prev, [field]: value }));
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
onGenerate(formData);
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-4xl max-h-[90vh]">
<DialogHeader>
<DialogTitle>📝 Generate Article</DialogTitle>
<DialogDescription>
Configure the parameters for article generation
</DialogDescription>
</DialogHeader>
<ScrollArea className="h-[calc(90vh-200px)] pr-4">
<form onSubmit={handleSubmit} className="space-y-6">
{/* 初始文章 */}
<div>
<Label htmlFor="input-article" className="mb-2">
初始文章 (Initial Article)
</Label>
<Textarea
id="input-article"
value={formData.inputArticle}
onChange={(e) => handleTextChange('inputArticle', e.target.value)}
placeholder="Enter an initial article or topic to base the generation on..."
className="min-h-[120px]"
/>
</div>
{/* 出版社 */}
<CheckboxField
label="出版社 (Publisher)"
fieldName="publisher"
value={formData.publisher}
onChange={(value: string) => handleCheckboxChange('publisher', value)}
options={PUBLISHER_OPTIONS}
columns={1}
/>
{/* 學生年級 + 課程範圍 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<CheckboxField
label="學生年級 (Grade Level)"
fieldName="grade"
value={formData.grade}
onChange={(value: string) => handleCheckboxChange('grade', value)}
options={GRADE_OPTIONS}
columns={1}
/>
<CheckboxField
label="課程範圍 (Unit Range)"
fieldName="unit"
value={formData.unit}
onChange={(value: string) => handleCheckboxChange('unit', value)}
options={UNIT_OPTIONS}
columns={1}
/>
</div>
{/* 文法範圍 + 主題範圍 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<CheckboxField
label="文法範圍 (Grammar Focus)"
fieldName="grammar"
value={formData.grammar}
onChange={(value: string) => handleCheckboxChange('grammar', value)}
options={GRAMMAR_OPTIONS}
columns={1}
/>
<CheckboxField
label="主題範圍 (Topic)"
fieldName="topic"
value={formData.topic}
onChange={(value: string) => handleCheckboxChange('topic', value)}
options={TOPIC_OPTIONS}
columns={1}
/>
</div>
{/* 單字列表 */}
<div>
<Label htmlFor="textbook-vocab" className="mb-2">
課本單字列表 (Textbook Vocabulary)
</Label>
<Textarea
id="textbook-vocab"
value={formData.textbookVocab}
readOnly
placeholder="Select units to see vocabulary"
className="bg-muted"
/>
</div>
{/* 額外單字列表 */}
<div>
<Label htmlFor="additional-vocab" className="mb-2">
額外單字列表 (Additional Vocabulary)
</Label>
<Textarea
id="additional-vocab"
value={formData.additionalVocab}
onChange={(e) => handleTextChange('additionalVocab', e.target.value)}
placeholder="Enter additional vocabulary words, separated by commas"
/>
</div>
</form>
</ScrollArea>
<DialogFooter>
<Button type="button" variant="outline" onClick={onClose}>
Cancel
</Button>
<Button
type="submit"
onClick={handleSubmit}
disabled={isGenerating}
>
{isGenerating && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{isGenerating ? '生成中...' : '生成初始文章'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}