let currentPageCount = 1; let currentContentType = 'page'; let generationInProgress = false; let generatedPages = []; let isPremiumUser = false; function showMessage(message, type = "info") { console.log(`Showing message: ${message} (type: ${type})`); let container = document.getElementById("message-container"); // Si le container n'existe pas, le créer if (!container) { container = document.createElement("div"); container.id = "message-container"; const multiPageContainer = document.querySelector(".ai-multi-page-container"); if (multiPageContainer) { multiPageContainer.appendChild(container); } else { console.error('Multi-page container not found'); return; } } container.innerHTML = `
${message}
`; container.scrollIntoView({ behavior: "smooth" }); // Auto-hide after 5 seconds for info messages if (type === "info") { setTimeout(() => { if (container && container.parentNode) { container.innerHTML = ''; } }, 5000); } } function getCreditsPageUrl() { const base = (typeof aiBuilderVars !== 'undefined' && aiBuilderVars.adminBaseUrl) ? aiBuilderVars.adminBaseUrl : '/wp-admin/'; return `${base}admin.php?page=aibui-credits`; } function renderPremiumWarning(message) { const warningContainer = document.getElementById('premium-warning-container'); if (!warningContainer) { return; } warningContainer.innerHTML = `
${message} Go to Credits
`; } function disableMultiPageAccess(message) { const content = document.querySelector('.ai-multi-page-content'); if (content) { content.classList.add('ai-locked'); const interactiveElements = content.querySelectorAll('button, select, textarea, input'); interactiveElements.forEach((element) => { element.setAttribute('disabled', 'disabled'); element.setAttribute('aria-disabled', 'true'); }); } renderPremiumWarning(message); showMessage(message, 'error'); } async function ensurePremiumAccess() { try { // Create AbortController for timeout const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 20000); // 10 second timeout const tokenResponse = await fetch(ajaxurl, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce, signal: controller.signal, }); if (!tokenResponse.ok) { if (tokenResponse.status === 500) { disableMultiPageAccess("Server error: The request took too long. Please refresh the page and try again."); } else { disableMultiPageAccess("Unable to verify authentication. Please refresh the page."); } return false; } clearTimeout(timeoutId); const tokenData = await tokenResponse.json(); if (!tokenData.success || !tokenData.data || !tokenData.data.token) { disableMultiPageAccess("Please sign in to access the Multi Page Generator."); return false; } const jwtToken = tokenData.data.token; const response = await fetch(`${window.config.apiUrl}/user/profile`, { method: "GET", headers: { Authorization: `Bearer ${jwtToken}`, "Content-Type": "application/json", }, }); if (!response.ok) { disableMultiPageAccess("Unable to verify your subscription. Please refresh the page."); return false; } const profile = await response.json(); const user = profile?.user || profile?.data || profile; const plan = (user?.plan || '').toLowerCase(); if (plan !== 'premium' && plan !== 'creator') { disableMultiPageAccess("Multi Page Generator is available for Premium subscribers only."); return false; } isPremiumUser = true; return true; } catch (error) { if (typeof timeoutId !== 'undefined' && timeoutId) { clearTimeout(timeoutId); } console.error("Error verifying premium access:", error); // Handle timeout/abort errors if (error.name === 'AbortError' || error.message.includes('timeout')) { disableMultiPageAccess("Request timeout: The server took too long to respond. Please check your connection and try again."); } else { disableMultiPageAccess("Unable to verify your subscription at this time. Please try again later."); } return false; } } function setLoading(buttonId, isLoading) { const button = document.getElementById(buttonId); if (!button) { console.error(`Button with id '${buttonId}' not found`); return; } let loading = button.querySelector(".ai-loading"); // Si l'élément loading n'existe pas, le créer if (!loading) { loading = document.createElement("span"); loading.className = "ai-loading"; loading.style.display = "none"; button.appendChild(loading); } // Stocker le texte original dans un attribut data si pas déjà fait if (!button.dataset.originalText) { button.dataset.originalText = button.textContent.trim(); } if (isLoading) { // Ensure layout centers spinner and text button.style.display = 'inline-flex'; button.style.alignItems = 'center'; button.style.justifyContent = 'center'; loading.style.display = "inline-block"; loading.style.marginRight = '8px'; button.disabled = true; button.textContent = ""; button.appendChild(loading); const textSpan = document.createElement('span'); textSpan.className = 'ai-loading-text'; textSpan.style.marginLeft = '4px'; textSpan.textContent = button.dataset.originalText; button.appendChild(textSpan); } else { loading.style.display = "none"; button.disabled = false; button.style.display = ''; button.style.alignItems = ''; button.style.justifyContent = ''; button.textContent = button.dataset.originalText; } } function updateTotalCost() { const pageCountSelect = document.getElementById('page-count'); if (!pageCountSelect) { console.error('Page count select element not found'); return; } const pageCount = parseInt(pageCountSelect.value); const totalCost = pageCount * 75; const totalCostElement = document.getElementById('total-cost'); if (!totalCostElement) { console.error('Total cost element not found'); return; } totalCostElement.textContent = `${totalCost} credits`; } function generatePagePrompts() { if (!isPremiumUser) { showMessage('Premium subscription required to use the Multi Page Generator.', 'error'); return; } const pageCount = parseInt(document.getElementById('page-count').value); const container = document.getElementById('pages-prompts-container'); container.innerHTML = ''; for (let i = 1; i <= pageCount; i++) { const pageDiv = document.createElement('div'); pageDiv.className = 'ai-page-prompt-item'; pageDiv.innerHTML = `
0/1500 characters
`; container.appendChild(pageDiv); // Ajouter le listener pour le compteur de caractères const textarea = pageDiv.querySelector('textarea'); const counter = pageDiv.querySelector('.ai-char-counter span'); textarea.addEventListener('input', function () { counter.textContent = this.value.length; if (this.value.length > 1400) { counter.style.color = '#ff6b6b'; } else if (this.value.length > 1200) { counter.style.color = '#ffa726'; } else { counter.style.color = '#666'; } }); } document.getElementById('pages-config-section').style.display = 'block'; document.getElementById('generate-pages-btn').style.display = 'block'; } function validatePrompts() { const pageCount = parseInt(document.getElementById('page-count').value); for (let i = 1; i <= pageCount; i++) { const prompt = document.getElementById(`page-${i}-prompt`).value.trim(); if (!prompt) { showMessage(`Please enter a prompt for page ${i}`, 'error'); return false; } if (prompt.length > 1500) { showMessage(`Prompt for page ${i} is too long (max 1500 characters)`, 'error'); return false; } } return true; } async function generatePages() { if (!isPremiumUser) { showMessage('Premium subscription required to use the Multi Page Generator.', 'error'); return; } if (generationInProgress) return; if (!validatePrompts()) return; generationInProgress = true; setLoading('generate-pages-btn', true); const pageCount = parseInt(document.getElementById('page-count').value); const contentType = document.getElementById('content-type').value; // Collect prompts const prompts = []; for (let i = 1; i <= pageCount; i++) { prompts.push(document.getElementById(`page-${i}-prompt`).value.trim()); } // Show progress section document.getElementById('generation-progress-section').style.display = 'block'; const progressContainer = document.getElementById('generation-progress'); progressContainer.innerHTML = ''; // Create progress items for (let i = 1; i <= pageCount; i++) { const progressItem = document.createElement('div'); progressItem.className = 'ai-progress-item'; progressItem.id = `progress-${i}`; progressItem.innerHTML = `
Page ${i} Waiting...
`; progressContainer.appendChild(progressItem); } // Generate pages one by one const results = []; for (let i = 0; i < pageCount; i++) { const pageNumber = i + 1; const statusElement = document.getElementById(`status-${pageNumber}`); const fillElement = document.getElementById(`fill-${pageNumber}`); try { statusElement.textContent = 'Generating...'; statusElement.style.color = '#ffa726'; fillElement.style.width = '0%'; fillElement.style.backgroundColor = '#ffa726'; const result = await generateSinglePage(prompts[i], contentType, pageNumber); if (result.success) { statusElement.textContent = 'Completed'; statusElement.style.color = '#4caf50'; fillElement.style.width = '100%'; fillElement.style.backgroundColor = '#4caf50'; results.push(result); } else { statusElement.textContent = result.error || 'Failed'; statusElement.style.color = '#f44336'; fillElement.style.backgroundColor = '#f44336'; results.push({ success: false, error: result.error }); } } catch (error) { console.error(`Error generating page ${pageNumber}:`, error); statusElement.textContent = 'Error'; statusElement.style.color = '#f44336'; fillElement.style.backgroundColor = '#f44336'; results.push({ success: false, error: error.message }); } // Small delay between pages if (i < pageCount - 1) { await new Promise(resolve => setTimeout(resolve, 1000)); } } // Show results showResults(results); generationInProgress = false; setLoading('generate-pages-btn', false); } // Fonction pour simuler la barre de progression function simulateProgress(fillElement, durationMs = 45000) { let currentProgress = 0; const targetProgress = 90; const startTime = Date.now(); let progressInterval; let slowProgressInterval; let isPhase2 = false; // Phase 1: 0% à 90% en 30 secondes de manière saccadée progressInterval = setInterval(() => { if (isPhase2) return; const elapsed = Date.now() - startTime; const baseProgress = Math.min((elapsed / durationMs) * targetProgress, targetProgress); // Ajouter des variations saccadées (uniquement positives pour ne pas reculer) const jitter = Math.random() * 2; // Entre 0% et 2% currentProgress = Math.min(baseProgress + jitter, targetProgress); // S'assurer que la progression ne recule jamais const currentWidth = parseFloat(fillElement.style.width) || 0; currentProgress = Math.max(currentProgress, currentWidth); fillElement.style.width = currentProgress + '%'; // Quand on arrive à 90%, passer à la phase lente if (currentProgress >= targetProgress) { clearInterval(progressInterval); isPhase2 = true; // Phase 2: Avancer très lentement de 90% vers ~95% slowProgressInterval = setInterval(() => { currentProgress = Math.min(currentProgress + 0.05, 95); fillElement.style.width = currentProgress + '%'; }, 1000); // +0.05% toutes les secondes (très lent) } }, 200); // Mise à jour toutes les 200ms pour un effet fluide mais saccadé // Fonction pour compléter à 100% return { complete: () => { clearInterval(progressInterval); clearInterval(slowProgressInterval); fillElement.style.width = '100%'; } }; } async function generateSinglePage(prompt, contentType, pageNumber) { if (!isPremiumUser) { return { success: false, error: 'Premium subscription required' }; } // Démarrer la simulation de progression const fillElement = document.getElementById(`fill-${pageNumber}`); const progressSimulator = simulateProgress(fillElement); let timeoutId; try { // Get JWT token with timeout const controller = new AbortController(); timeoutId = setTimeout(() => controller.abort(), 20000); // 10 second timeout const tokenResponse = await fetch(ajaxurl, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce, signal: controller.signal, }); clearTimeout(timeoutId); if (!tokenResponse.ok) { if (tokenResponse.status === 500) { progressSimulator.complete(); throw new Error("Server error: The request took too long or encountered an error. Please try again."); } progressSimulator.complete(); throw new Error(`HTTP error! status: ${tokenResponse.status}`); } const tokenData = await tokenResponse.json(); if (!tokenData.success || !tokenData.data.token) { progressSimulator.complete(); throw new Error("No authentication token found"); } const jwtToken = tokenData.data.token; // Call the AI API (JSON blocks response) const response = await fetch(`${window.config.apiUrl}/ai-transform-page/v2-page-generation`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${jwtToken}`, }, body: JSON.stringify({ userPrompt: prompt, pageContent: "", // Kept for compatibility wooCommerceInstalled: !!(typeof aiBuilderVars !== 'undefined' && aiBuilderVars.wooCommerceInstalled && aiBuilderVars.wooCommerceInstalled !== '0'), activeThemeName: (typeof aiBuilderVars !== 'undefined' && aiBuilderVars.activeThemeName) ? aiBuilderVars.activeThemeName : '', sitePlugins: (typeof aiBuilderVars !== 'undefined' && Array.isArray(aiBuilderVars.sitePlugins)) ? aiBuilderVars.sitePlugins.slice(0, 15) : [], wordpressVersion: (typeof aiBuilderVars !== 'undefined' && aiBuilderVars.wordpressVersion) ? String(aiBuilderVars.wordpressVersion) : '', }), }); const data = await response.json(); if (response.status === 402) { progressSimulator.complete(); return { success: false, error: "Not enough credits" }; } if (data.error === "not-enough-credits") { progressSimulator.complete(); return { success: false, error: "Not enough credits" }; } if (!data.pageContent) { progressSimulator.complete(); return { success: false, error: "No content generated" }; } // Save generation (Pending review) const generationPayload = { id: `${Date.now()}_${Math.random().toString(36).slice(2, 10)}`, title: data.postTitle || `Generated Page ${pageNumber}`, metaDesc: data.postMetaDesc || '', cssContent: data.cssContent || '', jsContent: data.jsContent || '', blocksJson: Array.isArray(data.pageContent) ? data.pageContent : [], }; const saveRes = await fetch(ajaxurl, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: `action=aibui_save_generation&nonce=${aiBuilderVars.nonce}&payload=${encodeURIComponent(JSON.stringify(generationPayload))}`, }); const saveData = await saveRes.json(); progressSimulator.complete(); if (!saveData.success) { return { success: false, error: saveData.data || 'Failed to save generation' }; } return { success: true, generation: saveData.data, pageTitle: generationPayload.title, }; } catch (error) { if (timeoutId) { clearTimeout(timeoutId); } console.error("Error generating page:", error); progressSimulator.complete(); // Handle timeout/abort errors if (error.name === 'AbortError' || error.message.includes('timeout')) { return { success: false, error: "Request timeout: The server took too long to respond. Please check your connection and try again." }; } return { success: false, error: error.message }; } } function showResults(results) { const resultsSection = document.getElementById('results-section'); const resultsList = document.getElementById('generated-pages-list'); resultsSection.style.display = 'block'; resultsList.innerHTML = ''; let successCount = 0; results.forEach((result, index) => { const pageNumber = index + 1; const resultItem = document.createElement('div'); resultItem.className = 'ai-result-item'; if (result.success && result.generation) { successCount++; const gen = result.generation; const base = (typeof aiBuilderVars !== 'undefined' && aiBuilderVars.adminBaseUrl) ? aiBuilderVars.adminBaseUrl : '/wp-admin/'; const applyUrl = `${base}post-new.php?post_type=${currentContentType}&aibui_gen_id=${encodeURIComponent(gen.id)}`; resultItem.innerHTML = `

Page ${pageNumber}: ${gen.title}

Status: Pending review Open and create page
`; } else { resultItem.innerHTML = `

Page ${pageNumber}: Failed

${result.error}

`; } resultsList.appendChild(resultItem); }); // Show summary message if (successCount > 0) { showMessage(`Successfully generated ${successCount} out of ${results.length} pages!`, 'success'); } else { showMessage('No pages were generated successfully.', 'error'); } } function resetForm() { document.getElementById('multi-page-form').reset(); document.getElementById('pages-config-section').style.display = 'none'; document.getElementById('generation-progress-section').style.display = 'none'; document.getElementById('results-section').style.display = 'none'; document.getElementById('generate-pages-btn').style.display = 'none'; updateTotalCost(); } // Event listeners document.addEventListener("DOMContentLoaded", function () { (async () => { console.log('Multi-page generator loaded'); // Debug: Check if config is loaded console.log('window.config:', window.config); console.log('window.config.apiUrl:', window.config?.apiUrl); if (!window.config || !window.config.apiUrl) { console.warn('Config not loaded, using fallback configuration'); // Fallback configuration window.config = { apiUrl: "https://api.wordpress-ai-builder.com/api" }; console.log('Using fallback config:', window.config); } // Debug: Check if CSS is loaded const testElement = document.createElement('div'); testElement.className = 'ai-multi-page-container'; testElement.style.display = 'none'; document.body.appendChild(testElement); const computedStyle = window.getComputedStyle(testElement); console.log('CSS loaded:', computedStyle.fontFamily !== ''); document.body.removeChild(testElement); // Debug: Check if AJAX variables are available console.log('ajaxurl:', window.ajaxurl); console.log('aiBuilderVars:', window.aiBuilderVars); if (!window.ajaxurl || !window.aiBuilderVars) { console.error('AJAX variables not loaded!'); showMessage('AJAX configuration not loaded. Please refresh the page.', 'error'); return; } const hasPremiumAccess = await ensurePremiumAccess(); if (!hasPremiumAccess) { return; } // Debug: Check if elements exist const pageCountSelect = document.getElementById('page-count'); const totalCostElement = document.getElementById('total-cost'); const startBtn = document.getElementById('start-generation-btn'); console.log('Page count select found:', !!pageCountSelect); console.log('Total cost element found:', !!totalCostElement); console.log('Start button found:', !!startBtn); if (pageCountSelect) { // Page count change pageCountSelect.addEventListener('change', function () { console.log('Page count changed to:', this.value); updateTotalCost(); }); } else { console.error('Page count select element not found'); } // Content type change const contentTypeSelect = document.getElementById('content-type'); if (contentTypeSelect) { contentTypeSelect.addEventListener('change', function () { currentContentType = this.value; console.log('Content type changed to:', this.value); }); } // Start generation button if (startBtn) { startBtn.addEventListener('click', function (e) { e.preventDefault(); console.log('Start generation button clicked'); generatePagePrompts(); }); } else { console.error('Start generation button not found'); } // Generate pages button const generateBtn = document.getElementById('generate-pages-btn'); if (generateBtn) { generateBtn.addEventListener('click', generatePages); } // Generate more button const generateMoreBtn = document.getElementById('generate-more-btn'); if (generateMoreBtn) { generateMoreBtn.addEventListener('click', resetForm); } // Initialize console.log('Initializing total cost...'); updateTotalCost(); // Load existing generations history and render sections (async function loadGenerationsHistory() { try { const res = await fetch(ajaxurl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `action=aibui_get_generations&nonce=${aiBuilderVars.nonce}`, }); const data = await res.json(); if (!data.success) return; const gens = Array.isArray(data.data) ? data.data : []; let history = document.getElementById('history-section'); if (!history) { history = document.createElement('div'); history.id = 'history-section'; history.innerHTML = `

Generations history

Pending review

Applied

`; const container = document.querySelector('.ai-multi-page-container') || document.body; container.appendChild(history); } const pendingList = document.getElementById('history-pending-list'); const appliedList = document.getElementById('history-applied-list'); if (!pendingList || !appliedList) return; pendingList.innerHTML = ''; appliedList.innerHTML = ''; const adminBase = (typeof aiBuilderVars !== 'undefined' && aiBuilderVars.adminBaseUrl) ? aiBuilderVars.adminBaseUrl : '/wp-admin/'; gens.forEach((g) => { const wrap = document.createElement('div'); wrap.className = 'ai-history-item'; wrap.style.cssText = 'display:flex;align-items:center;padding:10px;border:1px solid #e5e7eb;border-radius:6px;margin-bottom:8px;gap:12px;'; const title = document.createElement('div'); title.innerHTML = `${g.title || 'Untitled'}
${g.createdAt || ''}`; const actions = document.createElement('div'); actions.style.cssText = 'margin-left:auto;display:flex;align-items:center;gap:10px;justify-content:flex-end;'; if (g.applied && g.pageId) { const editUrl = `${adminBase}post.php?post=${encodeURIComponent(g.pageId)}&action=edit`; actions.innerHTML = `Status: Applied Open page`; wrap.appendChild(title); wrap.appendChild(actions); appliedList.appendChild(wrap); } else { const applyUrl = `${adminBase}post-new.php?post_type=${currentContentType}&aibui_gen_id=${encodeURIComponent(g.id)}`; actions.innerHTML = `Status: Pending review Open and create page`; wrap.appendChild(title); wrap.appendChild(actions); pendingList.appendChild(wrap); } }); } catch (e) { // silent } })(); })(); });