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 = `
`;
}
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 = `
`;
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 = `
`;
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}
`;
} 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
`;
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
}
})();
})();
});