/** * Content Settings Page - 3 Tabs * Tabs: Content Generation, Publishing, Image Settings * Consolidated settings for content creation workflow */ import { useState, useEffect, useCallback } from 'react'; import { useLocation } from 'react-router-dom'; import { Save, Loader2, Image as ImageIcon, FileText, Send, Settings } from 'lucide-react'; import { Card } from '../../components/ui/card'; import Button from '../../components/ui/button/Button'; import { fetchAPI } from '../../services/api'; import { useToast } from '../../components/ui/toast/ToastContainer'; import SelectDropdown from '../../components/form/SelectDropdown'; import Label from '../../components/form/Label'; import Checkbox from '../../components/form/input/Checkbox'; import PageMeta from '../../components/common/PageMeta'; import PageHeader from '../../components/common/PageHeader'; import { BoxCubeIcon } from '../../icons'; type TabType = 'content' | 'publishing' | 'images'; interface ImageGenerationSettings { enabled: boolean; service: 'openai' | 'runware'; provider: string; model: string; runwareModel?: string; image_type: 'realistic' | 'artistic' | 'cartoon'; max_in_article_images: number; image_format: 'webp' | 'jpg' | 'png'; desktop_enabled: boolean; mobile_enabled: boolean; featured_image_size: string; desktop_image_size: string; } interface PublishingSettings { autoPublishEnabled: boolean; autoSyncEnabled: boolean; } interface ContentGenerationSettings { appendToPrompt: string; defaultTone: string; defaultLength: string; } // Map user-friendly quality to internal service/model configuration const QUALITY_TO_CONFIG: Record = { standard: { service: 'openai', model: 'dall-e-2' }, premium: { service: 'openai', model: 'dall-e-3' }, best: { service: 'runware', model: 'runware:97@1' }, }; // Map internal config back to user-friendly quality const getQualityFromConfig = (service?: string, model?: string): 'standard' | 'premium' | 'best' => { if (service === 'runware') return 'best'; if (model === 'dall-e-3') return 'premium'; return 'standard'; }; // Get available image sizes based on provider and model const getImageSizes = (provider: string, model: string) => { if (provider === 'runware') { return [ { value: '1280x832', label: '1280×832 pixels' }, { value: '1024x1024', label: '1024×1024 pixels' }, { value: '512x512', label: '512×512 pixels' }, ]; } else if (provider === 'openai') { if (model === 'dall-e-2') { return [ { value: '256x256', label: '256×256 pixels' }, { value: '512x512', label: '512×512 pixels' }, { value: '1024x1024', label: '1024×1024 pixels' }, ]; } else if (model === 'dall-e-3') { return [ { value: '1024x1024', label: '1024×1024 pixels' }, ]; } } return [{ value: '1024x1024', label: '1024×1024 pixels' }]; }; // Get tab from URL path function getTabFromPath(pathname: string): TabType { if (pathname.includes('/publishing')) return 'publishing'; if (pathname.includes('/images')) return 'images'; return 'content'; } export default function ContentSettingsPage() { const toast = useToast(); const location = useLocation(); const activeTab = getTabFromPath(location.pathname); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); // Content Generation Settings const [contentSettings, setContentSettings] = useState({ appendToPrompt: '', defaultTone: 'professional', defaultLength: 'medium', }); // Publishing Settings const [publishingSettings, setPublishingSettings] = useState({ autoPublishEnabled: false, autoSyncEnabled: false, }); // Image Quality const [imageQuality, setImageQuality] = useState<'standard' | 'premium' | 'best'>('premium'); // Image Generation Settings const [imageSettings, setImageSettings] = useState({ enabled: true, service: 'openai', provider: 'openai', model: 'dall-e-3', image_type: 'realistic', max_in_article_images: 2, image_format: 'webp', desktop_enabled: true, mobile_enabled: true, featured_image_size: '1024x1024', desktop_image_size: '1024x1024', }); // Get current provider/model from quality setting const getCurrentConfig = useCallback(() => { const config = QUALITY_TO_CONFIG[imageQuality]; return { service: config.service, model: config.model, }; }, [imageQuality]); // Get available sizes for current quality const availableSizes = getImageSizes( getCurrentConfig().service, getCurrentConfig().model ); useEffect(() => { loadSettings(); }, []); // Update image sizes when quality changes useEffect(() => { const config = getCurrentConfig(); const sizes = getImageSizes(config.service, config.model); const defaultSize = sizes.length > 0 ? sizes[0].value : '1024x1024'; const validSizes = sizes.map(s => s.value); const needsFeaturedUpdate = !validSizes.includes(imageSettings.featured_image_size); const needsDesktopUpdate = !validSizes.includes(imageSettings.desktop_image_size); if (needsFeaturedUpdate || needsDesktopUpdate) { setImageSettings(prev => ({ ...prev, service: config.service, provider: config.service, model: config.model, featured_image_size: needsFeaturedUpdate ? defaultSize : prev.featured_image_size, desktop_image_size: needsDesktopUpdate ? defaultSize : prev.desktop_image_size, })); } else { setImageSettings(prev => ({ ...prev, service: config.service, provider: config.service, model: config.model, })); } }, [imageQuality, getCurrentConfig]); const loadSettings = async () => { try { setLoading(true); // Load image generation settings const imageData = await fetchAPI('/v1/system/settings/integrations/image_generation/'); if (imageData) { const quality = getQualityFromConfig(imageData.service || imageData.provider, imageData.model); setImageQuality(quality); setImageSettings({ enabled: imageData.enabled !== false, service: imageData.service || imageData.provider || 'openai', provider: imageData.provider || imageData.service || 'openai', model: imageData.model || 'dall-e-3', runwareModel: imageData.runwareModel, image_type: imageData.image_type || 'realistic', max_in_article_images: imageData.max_in_article_images || 2, image_format: imageData.image_format || 'webp', desktop_enabled: imageData.desktop_enabled !== false, mobile_enabled: imageData.mobile_enabled !== false, featured_image_size: imageData.featured_image_size || '1024x1024', desktop_image_size: imageData.desktop_image_size || '1024x1024', }); } // Load content generation settings try { const contentData = await fetchAPI('/v1/system/settings/content/content_generation/'); if (contentData?.config) { setContentSettings({ appendToPrompt: contentData.config.append_to_prompt || '', defaultTone: contentData.config.default_tone || 'professional', defaultLength: contentData.config.default_length || 'medium', }); } } catch (err) { // Settings may not exist yet, use defaults console.log('Content generation settings not found, using defaults'); } // Load publishing settings try { const publishData = await fetchAPI('/v1/system/settings/content/publishing/'); if (publishData?.config) { setPublishingSettings({ autoPublishEnabled: publishData.config.auto_publish_enabled || false, autoSyncEnabled: publishData.config.auto_sync_enabled || false, }); } } catch (err) { // Settings may not exist yet, use defaults console.log('Publishing settings not found, using defaults'); } } catch (error: any) { console.error('Error loading content settings:', error); } finally { setLoading(false); } }; const handleSave = async () => { try { setSaving(true); if (activeTab === 'images') { const config = getCurrentConfig(); const configToSave = { enabled: imageSettings.enabled, service: config.service, provider: config.service, model: config.model, runwareModel: config.service === 'runware' ? config.model : undefined, image_type: imageSettings.image_type, max_in_article_images: imageSettings.max_in_article_images, image_format: imageSettings.image_format, desktop_enabled: imageSettings.desktop_enabled, mobile_enabled: imageSettings.mobile_enabled, featured_image_size: imageSettings.featured_image_size, desktop_image_size: imageSettings.desktop_image_size, }; await fetchAPI('/v1/system/settings/integrations/image_generation/save/', { method: 'POST', body: JSON.stringify(configToSave), }); } // Save content generation settings if (activeTab === 'content') { await fetchAPI('/v1/system/settings/content/content_generation/save/', { method: 'POST', body: JSON.stringify({ config: { append_to_prompt: contentSettings.appendToPrompt, default_tone: contentSettings.defaultTone, default_length: contentSettings.defaultLength, } }), }); } // Save publishing settings if (activeTab === 'publishing') { await fetchAPI('/v1/system/settings/content/publishing/save/', { method: 'POST', body: JSON.stringify({ config: { auto_publish_enabled: publishingSettings.autoPublishEnabled, auto_sync_enabled: publishingSettings.autoSyncEnabled, } }), }); } toast.success('Settings saved successfully'); } catch (error: any) { console.error('Error saving settings:', error); toast.error(`Failed to save settings: ${error.message}`); } finally { setSaving(false); } }; const tabTitles: Record = { content: 'Content Generation', publishing: 'Publishing', images: 'Image Settings', }; if (loading) { return (
Loading settings...
); } return (
, color: 'blue' }} parent="Content Settings" /> {/* Tab Content */}
{/* Content Generation Tab */} {activeTab === 'content' && (

Content Generation

Customize how your articles are written