import { useState, useEffect } from '@wordpress/element'; import api from '../utils/api'; const { __ } = wp.i18n; const STEPS = [ { id: 1, label: __('What to Write', 'ai-bulk-post') }, { id: 2, label: __('AI Provider', 'ai-bulk-post') }, { id: 3, label: __('Prompts', 'ai-bulk-post') }, { id: 4, label: __('Schedule', 'ai-bulk-post') }, { id: 5, label: __('Publish', 'ai-bulk-post') }, ]; const CONTENT_LENGTH_OPTIONS = [ { value: 400, label: __('Short', 'ai-bulk-post'), desc: __('~300 words', 'ai-bulk-post') }, { value: 800, label: __('Medium', 'ai-bulk-post'), desc: __('~600 words', 'ai-bulk-post') }, { value: 1500, label: __('Long', 'ai-bulk-post'), desc: __('~1000 words', 'ai-bulk-post') }, { value: 3000, label: __('Very Long', 'ai-bulk-post'), desc: __('~2000 words', 'ai-bulk-post') }, ]; const PROMPT_PRESETS = { blog: { label: __('Blog Post', 'ai-bulk-post'), title: __('Write one engaging blog post title about [subject].', 'ai-bulk-post'), content: __('Write a comprehensive blog post about [subject]. Use HTML headings (h2, h3), bullet points, and clear paragraphs. Target length is [length] words. Include an introduction, main content sections, and a conclusion.', 'ai-bulk-post'), }, news: { label: __('News Article', 'ai-bulk-post'), title: __('Write a news headline about [subject].', 'ai-bulk-post'), content: __('Write a factual news article about [subject]. Use journalistic style with inverted pyramid structure. Include who, what, when, where, why. Target length is [length] words.', 'ai-bulk-post'), }, review: { label: __('Product Review', 'ai-bulk-post'), title: __('Write a product review title for [subject].', 'ai-bulk-post'), content: __('Write a detailed product review about [subject]. Include pros, cons, features, and a final verdict. Use HTML formatting with headings. Target length is [length] words.', 'ai-bulk-post'), }, tutorial: { label: __('Tutorial', 'ai-bulk-post'), title: __('Write a how-to tutorial title about [subject].', 'ai-bulk-post'), content: __('Write a step-by-step tutorial about [subject]. Use numbered steps, code examples where relevant, and clear explanations. Target length is [length] words.', 'ai-bulk-post'), }, }; const PROVIDER_NAMES = { openai: 'OpenAI', google: 'Google Gemini', grok: 'Grok', deepseek: 'DeepSeek', }; const POST_TYPES = { post: __('Posts', 'ai-bulk-post'), page: __('Pages', 'ai-bulk-post'), }; const defaultData = { title: '', provider: 'openai', model: 'gpt-5.6-luna', subject: '', length: 800, prompt_title: 'Write one blog post title about [subject].', prompt_content: 'Write blog post about [subject]. Use html characters and subheadings. And content length should be [length] words.', recurrence_type: 'interval', recurrence_interval: 1, recurrence_days: [], recurrence_time: '09:00', post_type: 'post', post_status: 'publish', categories: [], temperature: 0.7, max_tokens: 800, }; const dayOptions = [ { value: 'sun', label: __('Sun', 'ai-bulk-post') }, { value: 'mon', label: __('Mon', 'ai-bulk-post') }, { value: 'tue', label: __('Tue', 'ai-bulk-post') }, { value: 'wed', label: __('Wed', 'ai-bulk-post') }, { value: 'thu', label: __('Thu', 'ai-bulk-post') }, { value: 'fri', label: __('Fri', 'ai-bulk-post') }, { value: 'sat', label: __('Sat', 'ai-bulk-post') }, ]; const getCreativityLabel = (value) => { if (value <= 0.3) return __('Factual', 'ai-bulk-post'); if (value <= 0.8) return __('Balanced', 'ai-bulk-post'); if (value <= 1.3) return __('Creative', 'ai-bulk-post'); return __('Very Creative', 'ai-bulk-post'); }; const getClosestLengthOption = (value) => { return CONTENT_LENGTH_OPTIONS.reduce((prev, curr) => Math.abs(curr.value - value) < Math.abs(prev.value - value) ? curr : prev ); }; const getCreativityTip = (value) => { if (value <= 0.3) return __('Sticks closely to facts and instructions', 'ai-bulk-post'); if (value <= 0.8) return __('Balanced between accuracy and creativity', 'ai-bulk-post'); if (value <= 1.3) return __('More varied and creative output', 'ai-bulk-post'); return __('Highly creative, may deviate from source', 'ai-bulk-post'); }; export default function AgentForm({ agent, onSave, onClose }) { const [data, setData] = useState(defaultData); const [models, setModels] = useState({}); const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [errors, setErrors] = useState({}); const [currentStep, setCurrentStep] = useState(1); const hasProviders = Object.keys(models).length > 0; useEffect(() => { loadData(); if (agent) { setData((prev) => ({ ...prev, ...agent, categories: agent.categories || [], recurrence_days: agent.recurrence_days || [], })); } }, [agent]); const loadData = async () => { setLoading(true); try { const [modelsResult, catsResult] = await Promise.allSettled([ api.getModels(), api.getCategories(), ]); if (modelsResult.status === 'fulfilled') { setModels(modelsResult.value); } else { console.error('Failed to load models:', modelsResult.reason); } if (catsResult.status === 'fulfilled') { setCategories(catsResult.value); } else { console.error('Failed to load categories:', catsResult.reason); } } catch (err) { console.error('Failed to load form data:', err); } finally { setLoading(false); } }; const update = (field, value) => { setData((prev) => ({ ...prev, [field]: value })); setErrors((prev) => ({ ...prev, [field]: null })); }; const validateStep = (step) => { const newErrors = {}; if (step === 1) { if (!data.title.trim()) newErrors.title = __('Title is required.', 'ai-bulk-post'); if (!data.subject.trim()) newErrors.subject = __('Subject is required.', 'ai-bulk-post'); } if (step === 3) { if (!data.prompt_title.trim()) newErrors.prompt_title = __('Title prompt is required.', 'ai-bulk-post'); if (!data.prompt_content.trim()) newErrors.prompt_content = __( 'Content prompt is required.', 'ai-bulk-post' ); } setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleNext = () => { if (validateStep(currentStep)) { setCurrentStep((prev) => Math.min(prev + 1, 5)); } }; const handleBack = () => { setCurrentStep((prev) => Math.max(prev - 1, 1)); }; const handleSubmit = async () => { if (!validateStep(currentStep)) return; setSaving(true); try { await onSave(data); } catch (err) { setErrors({ submit: err.message }); } finally { setSaving(false); } }; const toggleDay = (day) => { const days = data.recurrence_days.includes(day) ? data.recurrence_days.filter((d) => d !== day) : [...data.recurrence_days, day]; update('recurrence_days', days); }; const applyPreset = (presetKey) => { const preset = PROMPT_PRESETS[presetKey]; if (preset) { update('prompt_title', preset.title); update('prompt_content', preset.content); } }; const renderStepContent = () => { if (loading) { return (
{getCreativityTip(data.temperature)}
{__( 'Approximate word count will be close to the target length.', 'ai-bulk-post' )}
{__( 'Choose a preset to auto-fill prompts, or customize below.', 'ai-bulk-post' )}
{__('Use [subject] as placeholder.', 'ai-bulk-post')}
{__('No categories found.', 'ai-bulk-post')}
)} {categories.map((cat) => ( ))}