| | '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; |
| | } |
| |
|
| | |
| | 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: '' |
| | }); |
| |
|
| | |
| | useEffect(() => { |
| | if (isOpen) { |
| | setFormData({ |
| | publisher: [], |
| | grade: [], |
| | unit: [], |
| | textbookVocab: '', |
| | additionalVocab: '', |
| | grammar: [], |
| | topic: [], |
| | inputArticle: '' |
| | }); |
| | } |
| | }, [isOpen]); |
| |
|
| | |
| | useEffect(() => { |
| | if (formData.grade.length > 0 && formData.unit.length > 0 && formData.publisher.length > 0) { |
| | |
| | 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> |
| | ); |
| | } |