Passer au contenu principal

Aperçu

Accédez aux données des produits via deux méthodes :
  • getStore() - Retourne tous les produits de la boutique (inclus dans la réponse de la boutique)
  • getProduct() - Récupère un seul produit par ID ou slug
  • getProductReviews() - Obtient les avis paginés pour un produit

Obtenir tous les produits

Les produits sont inclus dans la réponse de la boutique :
const response = await komerza.getStore();

if (response.success) {
  const products = response.data.products;

  products.forEach((product) => {
    console.log(product.name, product.variants.length, "variantes");
  });
}

Obtenir un produit individuel

Récupérer un produit par ID ou slug :
const response = await komerza.getProduct("product-id-or-slug");

Paramètres

idOrSlug
string
requis
L’ID unique du produit (UUID) ou le slug URL

Exemple

// Par ID
const byId = await komerza.getProduct("550e8400-e29b-41d4-a716-446655440000");

// Par slug
const bySlug = await komerza.getProduct("premium-license");

if (bySlug.success) {
  const product = bySlug.data;
  console.log(product.name);
  console.log(product.description);
  console.log(product.variants);
}

Objet Product

interface Product {
  id: string; // Identifiant unique
  name: string; // Nom du produit
  description: string; // Description (supporte le markdown)
  slug?: string; // Slug adapté à l'URL
  imageNames: string[]; // Noms de fichiers des images du produit (voir page Images)
  rating: number; // Note moyenne des avis
  order: number; // Ordre d'affichage
  visibility: number; // 0=Public, 1=Non répertorié, 2=Privé
  storeId: string; // ID de la boutique parente
  variants: Variant[]; // Variantes du produit
  dateCreated: string; // Horodatage ISO 8601
}

Variantes

Chaque produit possède une ou plusieurs variantes. Chaque variante a son propre prix, stock et paramètres :
interface Variant {
  id: string; // ID de la variante
  name: string; // Nom de la variante
  productId: string; // ID du produit parent
  storeId: string; // ID de la boutique
  cost: number; // Prix dans la devise de la boutique
  stock: number; // Stock disponible
  stockMode: number; // Mode de calcul du stock (voir ci-dessous)
  minimumQuantity: number; // Quantité minimale d'achat (par défaut : 1)
  maximumQuantity: number; // Quantité maximale d'achat (-1 = illimité)
  order: number; // Ordre d'affichage
  imageNames: string[]; // Noms de fichiers des images spécifiques à la variante
  type: number; // 0=Unique, 1=Abonnement
  subscriptionPeriod?: string; // Durée de l'abonnement si applicable
  requireDiscordAuthorization: boolean;
  dateCreated: string;
}

Mode de calcul du stock

Le champ stockMode détermine comment la disponibilité du stock est calculée :
ValeurModeDescription
0CalculéLe stock est automatiquement calculé à partir des articles disponibles
1IgnoréLe stock n’est pas suivi — toujours disponible
2FixeLe stock est défini manuellement et décrémenté à l’achat
Voir l’enum Stock Calculation Mode pour les détails complets.

Affichage des images

Les imageNames des produits et variantes contiennent des noms de fichiers, pas des URLs complètes. Consultez la page Images pour savoir comment construire les URLs complètes.

Afficher les variantes

async function afficherProduit(productId) {
  const [productResponse, formatter] = await Promise.all([
    komerza.getProduct(productId),
    komerza.createFormatter(),
  ]);

  if (!productResponse.success) return;

  const product = productResponse.data;

  // Trier les variantes par ordre
  const variants = product.variants.sort((a, b) => a.order - b.order);

  variants.forEach((variant) => {
    const price = formatter.format(variant.cost);
    const inStock = variant.stockMode === 1 || variant.stock > 0;

    console.log(`${variant.name}: ${price}`);
    console.log(`  Stock: ${inStock ? "Disponible" : "Rupture de stock"}`);
    console.log(`  Qté min: ${variant.minimumQuantity}`);
    console.log(
      `  Qté max: ${
        variant.maximumQuantity === -1 ? "Illimité" : variant.maximumQuantity
      }`,
    );
  });
}

Sélection de variante

<select id="variant-select" onchange="updatePrice()">
  <!-- Rempli dynamiquement -->
</select>
<span id="price"></span>
<button onclick="addToCart()">Ajouter au panier</button>

<script>
  let currentProduct;
  let formatter;

  async function loadProduct(productId) {
    [{ data: currentProduct }, formatter] = await Promise.all([
      komerza.getProduct(productId),
      komerza.createFormatter(),
    ]);

    const select = document.getElementById("variant-select");
    select.innerHTML = currentProduct.variants
      .map(
        (v) =>
          `<option value="${v.id}">${v.name} - ${formatter.format(
            v.cost,
          )}</option>`,
      )
      .join("");

    updatePrice();
  }

  function updatePrice() {
    const variantId = document.getElementById("variant-select").value;
    const variant = currentProduct.variants.find((v) => v.id === variantId);
    document.getElementById("price").textContent = formatter.format(
      variant.cost,
    );
  }

  function addToCart() {
    const variantId = document.getElementById("variant-select").value;
    komerza.addToBasket(currentProduct.id, variantId);
  }
</script>

Avis produit

Obtenez les avis paginés pour un produit :
const response = await komerza.getProductReviews(productId, page);

Paramètres

productId
string
requis
L’ID unique du produit
page
number
requis
Numéro de page (indexé à partir de 1)

Retours

Retourne PaginatedApiResponse<Review> :
interface PaginatedApiResponse<Review> {
  success: boolean;
  pages: number; // Nombre total de pages
  data?: Review[]; // Tableau d'avis
  message?: string;
}

interface Review {
  id: string;
  rating: number; // 1-5 étoiles
  reason: string; // Texte de l'avis
  productId: string;
  reply?: string; // Réponse du marchand si disponible
  dateCreated: string;
}

Afficher les avis

async function afficherAvis(productId, page = 1) {
  const response = await komerza.getProductReviews(productId, page);

  if (!response.success) return;

  const container = document.getElementById("reviews");

  container.innerHTML = response.data
    .map(
      (review) => `
    <div class="review">
      <div class="rating">${"★".repeat(review.rating)}${"☆".repeat(
        5 - review.rating,
      )}</div>
      <p>${review.reason}</p>
      ${
        review.reply
          ? `<p class="reply"><strong>Réponse :</strong> ${review.reply}</p>`
          : ""
      }
      <time>${new Date(review.dateCreated).toLocaleDateString()}</time>
    </div>
  `,
    )
    .join("");

  // Pagination
  if (response.pages > 1) {
    container.innerHTML += `
      <div class="pagination">
        ${
          page > 1
            ? `<button onclick="afficherAvis('${productId}', ${
                page - 1
              })">Précédent</button>`
            : ""
        }
        <span>Page ${page} sur ${response.pages}</span>
        ${
          page < response.pages
            ? `<button onclick="afficherAvis('${productId}', ${
                page + 1
              })">Suivant</button>`
            : ""
        }
      </div>
    `;
  }
}

Images produit

Les images produit sont référencées par nom de fichier. Construisez l’URL complète :
function getProductImageUrl(storeId, productId, imageName) {
  return `https://cdn.komerza.com/stores/${storeId}/products/${productId}/${imageName}`;
}

// Utilisation
const product = response.data;
const imageUrl = getProductImageUrl(
  product.storeId,
  product.id,
  product.imageNames[0],
);

Galerie d’images

function afficherImagesProduct(product) {
  const gallery = document.getElementById("gallery");

  // Utiliser les images de variante si disponibles, sinon les images produit
  const images =
    product.variants[0].imageNames.length > 0
      ? product.variants[0].imageNames
      : product.imageNames;

  gallery.innerHTML = images
    .map(
      (img) => `
    <img 
      src="https://cdn.komerza.com/stores/${product.storeId}/products/${product.id}/${img}"
      alt="${product.name}"
      loading="lazy"
    />
  `,
    )
    .join("");
}

Gestion du stock

Vérifiez la disponibilité du stock avant d’ajouter au panier :
function peutAjouterAuPanier(variant, quantity) {
  // stockMode 1 = Ignoré (illimité)
  if (variant.stockMode === 1) return true;

  // Vérifier le stock disponible
  if (variant.stock < quantity) return false;

  // Vérifier les limites de quantité
  if (quantity < variant.minimumQuantity) return false;
  if (variant.maximumQuantity !== -1 && quantity > variant.maximumQuantity)
    return false;

  return true;
}

function getStatutStock(variant) {
  if (variant.stockMode === 1) return "En stock";
  if (variant.stock === 0) return "Rupture de stock";
  if (variant.stock < 10) return `Plus que ${variant.stock}`;
  return "En stock";
}

Exemple complet

<!DOCTYPE html>
<html>
  <head>
    <title>Page produit</title>
    <script src="https://cdn.komerza.com/komerza.min.js"></script>
    <style>
      .product {
        max-width: 600px;
        margin: 0 auto;
      }
      .gallery img {
        max-width: 100%;
      }
      .variants {
        margin: 20px 0;
      }
      .reviews {
        margin-top: 40px;
      }
      .review {
        border-bottom: 1px solid #eee;
        padding: 15px 0;
      }
      .rating {
        color: gold;
      }
    </style>
  </head>
  <body>
    <div class="product">
      <div id="gallery"></div>
      <h1 id="name"></h1>
      <p id="description"></p>
      <p id="rating"></p>

      <div class="variants">
        <select id="variant-select"></select>
        <span id="price"></span>
        <span id="stock"></span>
      </div>

      <div>
        <label
          >Quantité : <input type="number" id="quantity" value="1" min="1"
        /></label>
        <button id="add-btn" onclick="addToCart()">Ajouter au panier</button>
      </div>

      <div class="reviews">
        <h2>Avis</h2>
        <div id="reviews"></div>
      </div>
    </div>

    <script>
      komerza.init("your-store-id");

      let product;
      let formatter;

      async function loadProduct(idOrSlug) {
        const [productResponse, fmt] = await Promise.all([
          komerza.getProduct(idOrSlug),
          komerza.createFormatter(),
        ]);

        if (!productResponse.success) {
          alert("Produit introuvable");
          return;
        }

        product = productResponse.data;
        formatter = fmt;

        // Afficher les informations du produit
        document.getElementById("name").textContent = product.name;
        document.getElementById("description").textContent =
          product.description;
        document.getElementById("rating").textContent =
          `Note : ${product.rating}★`;

        // Afficher les images
        const images = product.imageNames;
        document.getElementById("gallery").innerHTML = images
          .map(
            (img) =>
              `<img src="https://cdn.komerza.com/stores/${product.storeId}/products/${product.id}/${img}" />`,
          )
          .join("");

        // Remplir les variantes
        const select = document.getElementById("variant-select");
        select.innerHTML = product.variants
          .map((v) => `<option value="${v.id}">${v.name}</option>`)
          .join("");
        select.onchange = updateVariantDisplay;

        updateVariantDisplay();
        loadReviews(1);
      }

      function updateVariantDisplay() {
        const variantId = document.getElementById("variant-select").value;
        const variant = product.variants.find((v) => v.id === variantId);

        document.getElementById("price").textContent = formatter.format(
          variant.cost,
        );

        // Statut du stock
        let stockText = "En stock";
        if (variant.stockMode !== 1) {
          if (variant.stock === 0) stockText = "Rupture de stock";
          else if (variant.stock < 10) stockText = `Plus que ${variant.stock}`;
        }
        document.getElementById("stock").textContent = stockText;

        // Mettre à jour les limites de quantité
        const qtyInput = document.getElementById("quantity");
        qtyInput.min = variant.minimumQuantity;
        qtyInput.max =
          variant.maximumQuantity === -1 ? 999 : variant.maximumQuantity;
        qtyInput.value = variant.minimumQuantity;

        // Désactiver le bouton si rupture de stock
        document.getElementById("add-btn").disabled =
          variant.stockMode !== 1 && variant.stock === 0;
      }

      function addToCart() {
        const variantId = document.getElementById("variant-select").value;
        const quantity = parseInt(document.getElementById("quantity").value);

        komerza.addToBasket(product.id, variantId, quantity);
        alert("Ajouté au panier !");
      }

      async function loadReviews(page) {
        const response = await komerza.getProductReviews(product.id, page);

        if (!response.success || response.data.length === 0) {
          document.getElementById("reviews").innerHTML =
            "<p>Aucun avis pour l'instant</p>";
          return;
        }

        document.getElementById("reviews").innerHTML = response.data
          .map(
            (review) => `
        <div class="review">
          <div class="rating">${"★".repeat(review.rating)}${"☆".repeat(
            5 - review.rating,
          )}</div>
          <p>${review.reason}</p>
          ${review.reply ? `<p><em>Réponse : ${review.reply}</em></p>` : ""}
        </div>
      `,
          )
          .join("");
      }

      // Charger le produit depuis l'URL ou par défaut
      const urlParams = new URLSearchParams(window.location.search);
      const productId = urlParams.get("product") || "your-default-product-slug";
      loadProduct(productId);
    </script>
  </body>
</html>

Étapes suivantes

Formatage des devises

Formater les prix dans la devise de votre boutique

Gestion du panier

Ajouter des produits au panier