import React, { useState, useEffect } from "react"; import { __ } from "@wordpress/i18n"; import { normalizeAIError } from "../../../utils/aiErrorMessage"; import Modal from "react-modal"; import { getSettingsData, generateFaqAnswer } from "../utils/function"; // Custom modal styles const customStyles = { overlay: { position: "fixed", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "rgba(35, 40, 45, 0.5)", zIndex: 9990, padding: 50, paddingTop: 70, display: "flex", flexDirection: "column", overflow: "auto", }, content: { width: "40rem", maxWidth: "90%", position: "static", height: "auto", overflow: "initial", margin: "auto", }, }; const FaqAIModalForm = ({ open, setShowFaqAIModalForm, // reFetchCategories, // setShowCategoryModal, // updateCategory, // setUpdateCategory, setFormFields, formFields, // handleAnswerChange }) => { const [generatedResponse, setGeneratedResponse] = useState(formFields); const [generatedAnswer, setGeneratedAnswer] = useState(null); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); const [contentGenerated, setContentGenerated] = useState(false); const [settings, setSettings] = useState(null); useEffect(() => { getSettingsData().then((getSettings) => { setSettings(getSettings); }).catch(function (error) { console.log(error); }); }, []); const resetErrors = () => { setError(null); }; const handleCancel = () => { resetErrors(); // setShowCategoryModal(false); setShowFaqAIModalForm(false); // setUpdateCategory(null); }; const highlightKeywords = (inputString, keywords) => { let modifiedString = inputString.replace(/<(h\d)(.*?)>(.*?)<\/\1>/g, '<$1$2>$3$1>'); const keywordArray = keywords.split(',').map(keyword => keyword.trim()); keywordArray.forEach(keyword => { modifiedString = modifiedString.replace(new RegExp(`\\b(${keyword})\\b`, 'gi'), '$1'); }); return modifiedString; } const getAPIKey = (settings) => { if (!settings) { return ''; } // Mirror the server-side ProviderFactory::key_field_for(): the key lives in // the field for the *selected* AI platform, not always OpenAI. OpenAI keeps // the legacy `ai_autowrite_api_key`; every other platform (gemini, claude, // deepseek, …) uses `ai_api_key_`. Checking only the OpenAI field // blocked "Write with AI" whenever another provider was configured. const platform = settings.ai_platform || 'openai'; const field = platform === 'openai' ? 'ai_autowrite_api_key' : `ai_api_key_${platform}`; return settings[field] || ''; } const handleSubmit = async (event) => { event.preventDefault(); const question = document.getElementById('betterdocs-ai-title').value; const keywords = document.getElementById('betterdocs-ai-keyword').value; try { setIsLoading(true); setError(null); // The prompt build, model selection and "Answer:" cleanup now happen // server-side; the OpenAI API key never leaves the server. const res = await generateFaqAnswer({ question, keywords }); const answer = res?.data?.answer || ""; setIsLoading(false); if (!answer) { setContentGenerated(false); setError(__("The AI returned no answer. Try again or rephrase your question.", "betterdocs")); return; } setContentGenerated(true); setGeneratedResponse(state => ({ ...state, question: question, aiAnswer: answer, })); setGeneratedAnswer(answer); } catch (error) { setIsLoading(false); setContentGenerated(false); setError(normalizeAIError(error)); } }; const handleKeep = () => { // Set `answer` (the field actually saved as post_content) directly to the AI // answer — do NOT rely on the editor's async aiValue effect to copy it across. // If that effect races the editor's init or the answer is unchanged, `answer` // stayed empty and the FAQ saved blank ("content not being saved"). aiAnswer is // kept so the editor still renders the content visually. setFormFields({ ...generatedResponse, answer: generatedResponse?.aiAnswer || generatedResponse?.answer || "", }); handleCancel(); }; return ( handleCancel()} style={customStyles} > {__("Write FAQ with BetterDocs AI", "betterdocs")} {__("Generate FAQs effortlessly with BetterDocs AI. Input your question and relevant keywords and let the system generate FAQs tailored to your needs.", "betterdocs")} {settings && !getAPIKey(settings) && ( {__("Please insert your", "betterdocs")}{" "} {__("AI API Key", "betterdocs")} {" "} {__('to use this "Write with AI" feature.', "betterdocs")} )} {error && ( {error} )} {__("Question", "betterdocs")} setFormFields((state) => ({ ...state, question: e.target.value.replace(/^\s+/, ""), })) } /> {__("Keywords", "betterdocs")} {generatedAnswer && ( {__("Generated FAQ", "betterdocs")} )} {isLoading ? __("Generating…", "betterdocs") : contentGenerated ? __("Regenerate FAQ", "betterdocs") : __("Generate FAQ", "betterdocs")} {contentGenerated && ( handleKeep(generatedResponse)} > {__("Keep", "betterdocs")} )} handleCancel()} > ); }; //Modal.setAppElement("#betterdocsFaqBuilder"); export default FaqAIModalForm;
{__("Generate FAQs effortlessly with BetterDocs AI. Input your question and relevant keywords and let the system generate FAQs tailored to your needs.", "betterdocs")}