# ai-builder/2.1.5/assets/js/credits.js

AI Builder – Generate pages, blocks, images &amp; translate with AI, version 2.1.5. 746 lines.

- Page: https://pluginprobe.com/plugins/ai-builder/2.1.5/code/assets/js/credits.js
- Raw: https://pluginprobe.com/plugins/ai-builder/2.1.5/raw/assets/js/credits.js
- Modified: 2025-11-12T15:01:08+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ai-builder/2.1.5/code/assets/js/credits.js#L10-L20`.

```javascript
let userData = null;
let hasSubscription = false;
let currentPlan = null;

// Charger les informations utilisateur au chargement
document.addEventListener("DOMContentLoaded", function () {
  // Vérifier les paramètres de succès dans l'URL
  checkSuccessParameters();

  // Attacher les événements aux boutons de plan (une seule fois au chargement)
  attachPlanButtonEvents();

  // Charger les informations utilisateur
  loadUserInfo();
});

// Fonction pour vérifier les paramètres de succès dans l'URL
function checkSuccessParameters() {
  const urlParams = new URLSearchParams(window.location.search);
  const type = urlParams.get("type");
  const sessionId = urlParams.get("session_id");

  if (type && sessionId) {
    if (type === "credits_success") {
      showMessage(
        "Credit purchase completed successfully! Your credits will be updated shortly.",
        "success"
      );
      // Recharger les données après un délai pour s'assurer que les crédits sont mis à jour
      setTimeout(() => {
        loadUserInfo();
      }, 3000);
      // Nettoyer l'URL après affichage du message
      setTimeout(() => {
        const newUrl =
          window.location.pathname +
          window.location.search
            .replace(/[?&]type=[^&]*&session_id=[^&]*/, "")
            .replace(/^&/, "?");
        window.history.replaceState({}, document.title, newUrl);
      }, 5000);
    } else if (type === "subscription_success") {
      showMessage(
        "Subscription activated successfully! Your subscription is now active.",
        "success"
      );
      // Recharger les données après un délai pour s'assurer que l'abonnement est mis à jour
      setTimeout(() => {
        loadUserInfo();
      }, 3000);
      // Nettoyer l'URL après affichage du message
      setTimeout(() => {
        const newUrl =
          window.location.pathname +
          window.location.search
            .replace(/[?&]type=[^&]*&session_id=[^&]*/, "")
            .replace(/^&/, "?");
        window.history.replaceState({}, document.title, newUrl);
      }, 5000);
    }
  }
}

// Fonction pour charger les informations utilisateur
async function loadUserInfo() {
  try {
    const tokenResponse = await fetch(ajaxurl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce,
    });

    const tokenData = await tokenResponse.json();

    if (!tokenData.success || !tokenData.data.token) {
      showMessage("Authentication failed", "error");
      return;
    }

    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) {
      userData = await response.json();
      displayUserInfo(userData?.user);
      // updateSubscriptionButton() n'est plus nécessaire car updatePlansDisplay() gère tout
    } else {
      showMessage("Failed to load user information", "error");
    }
  } catch (error) {
    console.error("Error loading user info:", error);
    showMessage("Network error while loading user information", "error");
  }
}

// Afficher les informations utilisateur
function displayUserInfo(data) {
  // Afficher les crédits
  const creditsDisplay = document.getElementById("current-credits");
  const creditsBreakdown = data.aiCredits || {
    onAccountCreation: 0,
    monthlySubscription: 0,
    paid: 0,
  };

  const totalCredits =
    creditsBreakdown.onAccountCreation +
    creditsBreakdown.monthlySubscription +
    creditsBreakdown.paid;

  if (creditsDisplay) {
    creditsDisplay.innerHTML = `
        <span class="credits-number">${totalCredits}</span>
        <span class="credits-label">credits</span>
    `;
  }

  // Afficher le plan
  const planDisplay = document.getElementById("current-plan");
  if (planDisplay) {
    const plan = data.plan || "basic";
    let resiliateText = "";
    if (data.resiliateAt) {
      const resiliateDate = new Date(data.resiliateAt);
      const now = new Date();
      const isEnded = resiliateDate < now.setHours(0, 0, 0, 0);
      if (isEnded) {
        resiliateText = `<span class="resiliate-badge">Subscription has ended on <strong>${resiliateDate.toLocaleDateString()}</strong></span>`;
      } else {
        resiliateText = `<span class="resiliate-badge">Subscription will end on <strong>${resiliateDate.toLocaleDateString()}</strong></span>`;
      }
    }
    planDisplay.innerHTML = `
        <span class="plan-badge ${plan}">${plan.charAt(0).toUpperCase() + plan.slice(1)
      }</span>
        ${resiliateText}
    `;
  }

  // Afficher le message dans la carte Subscription (section management)
  const subscriptionCard = document.querySelector(
    ".ai-subscription-actions .ai-action-content"
  );
  if (subscriptionCard) {
    let resiliateMsg = subscriptionCard.querySelector(".resiliate-badge");
    if (data.resiliateAt) {
      if (!resiliateMsg) {
        resiliateMsg = document.createElement("div");
        resiliateMsg.className = "resiliate-badge";
        resiliateMsg.innerHTML = `Subscription will end on <strong>${new Date(
          data.resiliateAt
        ).toLocaleDateString()}</strong>`;
        subscriptionCard.appendChild(resiliateMsg);
      } else {
        resiliateMsg.innerHTML = `Subscription will end on <strong>${new Date(
          data.resiliateAt
        ).toLocaleDateString()}</strong>`;
      }
    } else if (resiliateMsg) {
      resiliateMsg.remove();
    }
  }

  // Vérifier si l'utilisateur a un abonnement
  hasSubscription = data.plan && data.plan !== "basic";
  currentPlan = data.plan || "basic";
  window.hasResiliate = !!data.resiliateAt;

  // Mettre à jour l'affichage de la section Buy Credits
  updateCreditPurchaseSection();

  // Mettre à jour l'affichage des plans
  updatePlansDisplay();
}

// Attacher les événements aux boutons de plan
function attachPlanButtonEvents() {
  // Utiliser la délégation d'événements pour éviter les problèmes de duplication
  const plansContainer = document.getElementById("subscription-plans-container");
  if (plansContainer) {
    // Retirer l'ancien listener s'il existe
    plansContainer.removeEventListener("click", handlePlanButtonClick);
    // Ajouter le nouveau listener
    plansContainer.addEventListener("click", handlePlanButtonClick);
  }

  // Bouton d'annulation
  const cancelBtn = document.getElementById("subscription-btn");
  if (cancelBtn) {
    cancelBtn.onclick = showCancelModal;
  }
}

// Gestionnaire de clic pour les boutons de plan (délégation d'événements)
function handlePlanButtonClick(event) {
  const button = event.target.closest(".ai-plan-btn");
  if (!button || button.disabled) return;

  const subscriptionType = button.getAttribute("data-subscription-type");
  if (subscriptionType) {
    // Vérifier dynamiquement l'état de l'abonnement
    if (hasSubscription && !window.hasResiliate) {
      // Utilisateur avec abonnement actif -> changer de plan
      handleChangeSubscription(subscriptionType, button);
    } else {
      // Utilisateur sans abonnement ou abonnement annulé -> nouveau checkout
      handleSubscription(subscriptionType, button);
    }
  }
}

// Mettre à jour l'affichage des plans
function updatePlansDisplay() {
  const planWrappers = document.querySelectorAll(".ai-plan-card-wrapper");
  const cancelCard = document.getElementById("cancel-subscription-card");

  if (!planWrappers || planWrappers.length === 0) {
    return; // Les plans ne sont pas encore chargés
  }

  planWrappers.forEach((wrapper) => {
    const planType = wrapper.getAttribute("data-plan");
    const button = wrapper.querySelector(".ai-plan-btn");
    if (!button) return;

    const btnText = button.querySelector(".btn-text");
    if (!btnText) return;

    // Réinitialiser l'état
    wrapper.setAttribute("data-current-plan", "false");
    button.classList.remove("current-plan");
    button.disabled = false;

    if (hasSubscription && !window.hasResiliate) {
      // Utilisateur avec abonnement actif
      if (planType === currentPlan) {
        // Plan actuel
        wrapper.setAttribute("data-current-plan", "true");
        button.classList.add("current-plan");
        btnText.textContent = "Current Plan";
        button.disabled = true;
      } else {
        // Autre plan -> option de changement
        btnText.textContent = `Switch to ${planType.charAt(0).toUpperCase() + planType.slice(1)}`;
        button.disabled = false;
      }
    } else if (hasSubscription && window.hasResiliate) {
      // Abonnement annulé mais pas encore terminé
      btnText.textContent = `Choose ${planType.charAt(0).toUpperCase() + planType.slice(1)}`;
      button.disabled = false;
    } else {
      // Pas d'abonnement
      btnText.textContent = `Choose ${planType.charAt(0).toUpperCase() + planType.slice(1)}`;
      button.disabled = false;
    }
  });

  // Afficher/masquer la carte d'annulation
  if (cancelCard) {
    if (hasSubscription && !window.hasResiliate) {
      cancelCard.style.display = "block";
    } else {
      cancelCard.style.display = "none";
    }
  }
}

// Mettre à jour le bouton d'abonnement (fonction conservée pour compatibilité mais non utilisée)
// L'affichage des plans est maintenant géré par updatePlansDisplay()
// Cette fonction peut être utilisée pour le bouton d'annulation si nécessaire
function updateSubscriptionButton() {
  const btn = document.getElementById("subscription-btn");
  if (!btn) return; // Sécurité : le bouton n'existe pas

  // Reconstruit le HTML interne du bouton à chaque fois
  btn.innerHTML = `
        <span class="ai-loading" style="display: none;"></span>
        <span class="btn-text"></span>
    `;
  const btnText = btn.querySelector(".btn-text");
  const loading = btn.querySelector(".ai-loading");
  if (!btnText || !loading) return; // Sécurité : structure inattendue

  if (hasSubscription && window.hasResiliate) {
    btnText.textContent = "Reactivate Subscription";
    btn.className = "ai-primary-btn ai-reactivate-btn";
    btn.onclick = handleReactivateSubscription;
  } else if (hasSubscription) {
    btnText.textContent = "Cancel Subscription";
    btn.className = "ai-danger-btn";
    btn.onclick = showCancelModal;
  } else {
    // Ce cas ne devrait plus se produire car nous avons maintenant les boutons de plan individuels
    btnText.textContent = "Get Subscription";
    btn.className = "ai-primary-btn";
    btn.onclick = null; // Ne pas assigner handleSubscription sans paramètre
  }
}

// Fonction pour réactiver l'abonnement
async function handleReactivateSubscription() {
  setLoading("subscription-btn", true);
  try {
    const tokenResponse = await fetch(ajaxurl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce,
    });
    const tokenData = await tokenResponse.json();
    const jwtToken = tokenData.data.token;
    const response = await fetch(
      window.config.apiUrl + "/payments/resume-subscription",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${jwtToken}`,
          "Content-Type": "application/json",
        },
      }
    );
    const data = await response.json();
    if (response.ok) {
      showMessage("Subscription reactivated successfully!", "success");
      setTimeout(() => {
        loadUserInfo();
      }, 1000);
    } else {
      showMessage(data.message || "Failed to reactivate subscription", "error");
    }
  } catch (error) {
    console.error("Error reactivating subscription:", error);
    showMessage("Network error while reactivating subscription", "error");
  } finally {
    setLoading("subscription-btn", false);
  }
}

// Mettre à jour l'affichage de la section Buy Credits
function updateCreditPurchaseSection() {
  const creditCard = document.getElementById("credit-purchase-card");
  const buyCreditsBtn = document.getElementById("buy-credits-btn");
  const subscriptionMessage = document.getElementById(
    "subscription-required-message"
  );
  const sectionHeader = document.querySelector(
    "#credit-purchase-section .ai-section-header p"
  );

  if (hasSubscription) {
    // Utilisateur avec abonnement - afficher normalement
    creditCard.classList.remove("ai-disabled");
    buyCreditsBtn.disabled = false;
    buyCreditsBtn.onclick = handleCreditPurchase;
    subscriptionMessage.style.display = "none";
    sectionHeader.textContent =
      "Purchase additional credits when you need them";
  } else {
    // Utilisateur sans abonnement - griser et afficher message
    creditCard.classList.add("ai-disabled");
    buyCreditsBtn.disabled = true;
    buyCreditsBtn.onclick = null;
    subscriptionMessage.style.display = "flex";
    // sectionHeader.textContent =
    //   "Active subscription required to purchase credits";
  }
}

// Gérer l'abonnement (nouveau checkout)
async function handleSubscription(subscriptionType, buttonElement) {
  if (!subscriptionType) {
    showMessage("Please select a subscription plan", "error");
    return;
  }

  // Désactiver tous les boutons pendant le traitement
  const planButtons = document.querySelectorAll(".ai-plan-btn");
  planButtons.forEach((btn) => {
    btn.disabled = true;
  });

  // Afficher le loading sur le bouton cliqué
  if (buttonElement) {
    const loading = buttonElement.querySelector(".ai-loading");
    const btnText = buttonElement.querySelector(".btn-text");
    if (loading) loading.style.display = "inline-block";
    if (btnText) {
      const originalText = btnText.textContent;
      btnText.textContent = "Processing...";
    }
  }

  try {
    const tokenResponse = await fetch(ajaxurl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce,
    });

    const tokenData = await tokenResponse.json();
    if (!tokenData.success || !tokenData.data.token) {
      showMessage("Authentication failed", "error");
      return;
    }

    const jwtToken = tokenData.data.token;

    const response = await fetch(
      window.config.apiUrl + "/payments/create-checkout-session-abo",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${jwtToken}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          subscriptionType: subscriptionType,
          urlFrom: window.location.href,
        }),
      }
    );

    const data = await response.json();

    if (response.ok && data.url) {
      window.location.href = data.url;
    } else {
      showMessage(
        data.message || "Failed to create subscription checkout",
        "error"
      );
      // Réactiver les boutons en cas d'erreur
      planButtons.forEach((btn) => {
        btn.disabled = false;
      });
      if (buttonElement) {
        const loading = buttonElement.querySelector(".ai-loading");
        const btnText = buttonElement.querySelector(".btn-text");
        if (loading) loading.style.display = "none";
        if (btnText) {
          btnText.textContent = buttonElement.getAttribute("data-subscription-type")
            ? `Choose ${buttonElement.getAttribute("data-subscription-type").charAt(0).toUpperCase() + buttonElement.getAttribute("data-subscription-type").slice(1)}`
            : "Choose Plan";
        }
      }
    }
  } catch (error) {
    console.error("Error creating subscription:", error);
    showMessage("Network error while creating subscription", "error");
    // Réactiver les boutons en cas d'erreur
    const planButtons = document.querySelectorAll(".ai-plan-btn");
    planButtons.forEach((btn) => {
      btn.disabled = false;
    });
    if (buttonElement) {
      const loading = buttonElement.querySelector(".ai-loading");
      const btnText = buttonElement.querySelector(".btn-text");
      if (loading) loading.style.display = "none";
      if (btnText) {
        btnText.textContent = buttonElement.getAttribute("data-subscription-type")
          ? `Choose ${buttonElement.getAttribute("data-subscription-type").charAt(0).toUpperCase() + buttonElement.getAttribute("data-subscription-type").slice(1)}`
          : "Choose Plan";
      }
    }
  }
}

// Gérer le changement d'abonnement
async function handleChangeSubscription(subscriptionType, buttonElement) {
  if (!subscriptionType) {
    showMessage("Please select a subscription plan", "error");
    return;
  }

  // Vérifier si c'est le même plan
  if (subscriptionType === currentPlan) {
    showMessage("You are already on this plan", "info");
    return;
  }

  // Désactiver tous les boutons pendant le traitement
  const planButtons = document.querySelectorAll(".ai-plan-btn");
  planButtons.forEach((btn) => {
    btn.disabled = true;
  });

  // Afficher le loading sur le bouton cliqué
  if (buttonElement) {
    const loading = buttonElement.querySelector(".ai-loading");
    const btnText = buttonElement.querySelector(".btn-text");
    if (loading) loading.style.display = "inline-block";
    if (btnText) {
      const originalText = btnText.textContent;
      btnText.textContent = "Switching...";
    }
  }

  try {
    const tokenResponse = await fetch(ajaxurl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce,
    });

    const tokenData = await tokenResponse.json();
    if (!tokenData.success || !tokenData.data.token) {
      showMessage("Authentication failed", "error");
      return;
    }

    const jwtToken = tokenData.data.token;

    const response = await fetch(
      window.config.apiUrl + "/payments/change-subscription",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${jwtToken}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          subscriptionType: subscriptionType,
        }),
      }
    );

    const data = await response.json();

    if (response.ok) {
      showMessage("Subscription changed successfully!", "success");
      // Recharger les informations utilisateur
      setTimeout(() => {
        loadUserInfo();
      }, 1000);
    } else {
      showMessage(
        data.message || "Failed to change subscription",
        "error"
      );
      // Réactiver les boutons en cas d'erreur
      planButtons.forEach((btn) => {
        btn.disabled = false;
      });
      if (buttonElement) {
        const loading = buttonElement.querySelector(".ai-loading");
        const btnText = buttonElement.querySelector(".btn-text");
        if (loading) loading.style.display = "none";
        if (btnText) {
          btnText.textContent = `Switch to ${subscriptionType.charAt(0).toUpperCase() + subscriptionType.slice(1)}`;
        }
      }
    }
  } catch (error) {
    console.error("Error changing subscription:", error);
    showMessage("Network error while changing subscription", "error");
    // Réactiver les boutons en cas d'erreur
    const planButtons = document.querySelectorAll(".ai-plan-btn");
    planButtons.forEach((btn) => {
      btn.disabled = false;
    });
    if (buttonElement) {
      const loading = buttonElement.querySelector(".ai-loading");
      const btnText = buttonElement.querySelector(".btn-text");
      if (loading) loading.style.display = "none";
      if (btnText) {
        btnText.textContent = `Switch to ${subscriptionType.charAt(0).toUpperCase() + subscriptionType.slice(1)}`;
      }
    }
  }
}

// Acheter des crédits
async function handleCreditPurchase() {
  try {
    const tokenResponse = await fetch(ajaxurl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce,
    });

    const tokenData = await tokenResponse.json();
    const jwtToken = tokenData.data.token;

    const urlFrom = window.location.href;
    const response = await fetch(
      window.config.apiUrl + "/payments/create-checkout-session-credits",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${jwtToken}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          urlFrom,
        }),
      }
    );

    const data = await response.json();

    if (response.ok && data.url) {
      window.location.href = data.url;
    } else {
      showMessage(data.message || "Failed to create credit checkout", "error");
    }
  } catch (error) {
    console.error("Error creating credit checkout:", error);
    showMessage("Network error while creating credit checkout", "error");
  }
}

// Accéder au compte Stripe
async function handleStripeAccount() {
  try {
    const tokenResponse = await fetch(ajaxurl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce,
    });

    const tokenData = await tokenResponse.json();
    const jwtToken = tokenData.data.token;

    const urlFrom = window.location.href;
    const response = await fetch(
      window.config.apiUrl + "/payments/stripe-customer-portal",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${jwtToken}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          urlFrom,
        }),
      }
    );

    const data = await response.json();

    if (response.ok && data.url) {
      window.open(data.url, "_blank");
    } else {
      showMessage(data.message || "Failed to access Stripe account", "error");
    }
  } catch (error) {
    console.error("Error accessing Stripe account:", error);
    showMessage("Network error while accessing Stripe account", "error");
  }
}

// Afficher la modal de confirmation
function showCancelModal() {
  document.getElementById("confirmation-modal").style.display = "flex";
}

// Fermer la modal
function closeModal() {
  document.getElementById("confirmation-modal").style.display = "none";
}

// Confirmer l'annulation de l'abonnement
async function confirmCancelSubscription() {
  const btn = document.querySelector(".ai-danger-btn");
  const loading = btn.querySelector(".ai-loading");
  const text = btn.textContent;

  loading.style.display = "inline-block";
  btn.textContent = "";
  btn.appendChild(loading);
  btn.appendChild(document.createTextNode(text));
  btn.disabled = true;

  try {
    const tokenResponse = await fetch(ajaxurl, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: "action=aibui_get_token&nonce=" + aiBuilderVars.nonce,
    });

    const tokenData = await tokenResponse.json();
    const jwtToken = tokenData.data.token;

    const response = await fetch(
      window.config.apiUrl + "/payments/cancel-subscription",
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${jwtToken}`,
          "Content-Type": "application/json",
        },
      }
    );

    const data = await response.json();

    if (response.ok) {
      showMessage("Subscription cancelled successfully", "success");
      closeModal();
      // Forcer l'état local pour l'UI
      window.hasResiliate = true;
      hasSubscription = false; // Mettre à jour l'état local
      // Recharger les informations utilisateur (qui va mettre à jour l'affichage via updatePlansDisplay)
      setTimeout(() => {
        loadUserInfo();
      }, 1000);
    } else {
      showMessage(data.message || "Failed to cancel subscription", "error");
    }
  } catch (error) {
    console.error("Error cancelling subscription:", error);
    showMessage("Network error while cancelling subscription", "error");
  } finally {
    loading.style.display = "none";
    btn.textContent = text;
    btn.disabled = false;
  }
}

// Fonctions utilitaires
function showMessage(message, type = "info") {
  const container = document.getElementById("message-container");
  container.innerHTML = `<div class="ai-message ${type}">${message}</div>`;
  container.scrollIntoView({ behavior: "smooth" });
}

function setLoading(buttonId, isLoading) {
  const button = document.getElementById(buttonId);
  const loading = button.querySelector(".ai-loading");
  const text = button.querySelector(".btn-text");

  if (isLoading) {
    loading.style.display = "inline-block";
    button.disabled = true;
  } else {
    loading.style.display = "none";
    button.disabled = false;
  }
}

```
