| | 'use client'; |
| |
|
| | import { useState, useEffect } from 'react'; |
| | import { ArticleGenerationModal, ArticleGenerationParams } from './ArticleGenerationModal'; |
| | import { Button } from '@/components/ui/button'; |
| | import { Checkbox } from '@/components/ui/checkbox'; |
| | import { Label } from '@/components/ui/label'; |
| | import { Textarea } from '@/components/ui/textarea'; |
| | import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; |
| | import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; |
| |
|
| | interface ArticleProps { |
| | className?: string; |
| | sourceArticle: string; |
| | onSourceArticleChange: (text: string) => void; |
| | isSourceLocked: boolean; |
| | onSourceLockedChange: (locked: boolean) => void; |
| | } |
| |
|
| | export function Article({ |
| | className = '', |
| | sourceArticle, |
| | onSourceArticleChange, |
| | isSourceLocked, |
| | onSourceLockedChange, |
| | }: ArticleProps) { |
| |
|
| | const [wordCount, setWordCount] = useState(0); |
| | const [isModalOpen, setIsModalOpen] = useState(false); |
| | const [isGeneratingArticle, setIsGeneratingArticle] = useState(false); |
| | const [isExpandOpen, setIsExpandOpen] = useState(false); |
| |
|
| | const updateWordCount = (text: string) => { |
| | const words = text.trim().split(/\s+/).length; |
| | setWordCount(text.trim() === '' ? 0 : words); |
| | }; |
| |
|
| | useEffect(() => { |
| | updateWordCount(sourceArticle); |
| | }, [sourceArticle]); |
| |
|
| | const handleSourceArticleChange = (text: string) => { |
| | if (!isSourceLocked) { |
| | onSourceArticleChange(text); |
| | } |
| | }; |
| |
|
| | const handleGenerateArticle = async (params: ArticleGenerationParams) => { |
| | setIsGeneratingArticle(true); |
| | try { |
| | |
| | const response = await fetch('/api/generate-article', { |
| | method: 'POST', |
| | headers: { 'Content-Type': 'application/json' }, |
| | body: JSON.stringify(params), |
| | }); |
| |
|
| | if (response.ok) { |
| | const { article } = await response.json(); |
| | onSourceArticleChange(article); |
| | setIsModalOpen(false); |
| | } else { |
| | console.error('Failed to generate article'); |
| | } |
| | } catch (error) { |
| | console.error('Error generating article:', error); |
| | } finally { |
| | setIsGeneratingArticle(false); |
| | } |
| | }; |
| |
|
| | return ( |
| | <Card className={`flex flex-col h-full ${className}`}> |
| | <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-4 px-6 pt-2"> |
| | <CardTitle className="text-lg font-semibold"> |
| | π Source Article |
| | </CardTitle> |
| | <div className="flex items-center space-x-4"> |
| | <Button |
| | onClick={() => setIsModalOpen(true)} |
| | disabled={isSourceLocked} |
| | size="sm" |
| | > |
| | β¨ Generate |
| | </Button> |
| | <span className="text-sm text-muted-foreground"> |
| | {wordCount} words |
| | </span> |
| | <div className="flex items-center space-x-2"> |
| | <Checkbox |
| | id="lock-source" |
| | checked={isSourceLocked} |
| | onCheckedChange={onSourceLockedChange} |
| | /> |
| | <Label htmlFor="lock-source" className="text-sm cursor-pointer"> |
| | π Lock |
| | </Label> |
| | </div> |
| | <Button |
| | onClick={() => setIsExpandOpen(true)} |
| | disabled={isSourceLocked} |
| | variant="outline" |
| | size="sm" |
| | > |
| | β€’ Expand |
| | </Button> |
| | </div> |
| | </CardHeader> |
| | |
| | <CardContent className="flex-1 px-6 pb-6 overflow-hidden"> |
| | <Textarea |
| | value={sourceArticle} |
| | onChange={(e) => handleSourceArticleChange(e.target.value)} |
| | placeholder="Paste or type your source article here (articles, passages, etc.)..." |
| | disabled={isSourceLocked} |
| | className="w-full h-full resize-none" |
| | /> |
| | </CardContent> |
| | |
| | <ArticleGenerationModal |
| | isOpen={isModalOpen} |
| | onClose={() => setIsModalOpen(false)} |
| | onGenerate={handleGenerateArticle} |
| | isGenerating={isGeneratingArticle} |
| | /> |
| | |
| | {/* Full-screen editor dialog for comfortable editing */} |
| | <Dialog open={isExpandOpen} onOpenChange={setIsExpandOpen}> |
| | <DialogContent className="w-[98vw] sm:max-w-none md:max-w-[90vw] h-[70vh] max-h-[95vh] p-0 flex flex-col"> |
| | <DialogHeader className="px-6 pt-6 pb-2"> |
| | <DialogTitle>π Edit Source Article</DialogTitle> |
| | </DialogHeader> |
| | <div className="flex-1 px-6 pb-6"> |
| | <Textarea |
| | value={sourceArticle} |
| | onChange={(e) => handleSourceArticleChange(e.target.value)} |
| | placeholder="Paste or type your source article here (articles, passages, etc.)..." |
| | disabled={isSourceLocked} |
| | className="w-full h-full resize-none" |
| | /> |
| | </div> |
| | </DialogContent> |
| | </Dialog> |
| | </Card> |
| | ); |
| | } |