Przejdź do głównej treści

Przegląd

Dostęp do danych produktów przez dwie metody:
  • getStore() - Zwraca wszystkie produkty w sklepie (zawarte w odpowiedzi sklepu)
  • getProduct() - Pobiera pojedynczy produkt po ID lub slug
  • getProductReviews() - Pobiera stronicowane recenzje dla produktu

Pobieranie wszystkich produktów

Produkty są zawarte w odpowiedzi sklepu:
const response = await komerza.getStore();

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

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

Pobieranie pojedynczego produktu

Pobierz produkt po ID lub slug:
const response = await komerza.getProduct("product-id-or-slug");

Parametry

idOrSlug
string
wymagane
Unikalny ID produktu (UUID) lub slug URL

Przykład

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

// Po 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);
}

Obiekt Product

interface Product {
  id: string; // Unikalny identyfikator
  name: string; // Nazwa produktu
  description: string; // Opis (obsługuje markdown)
  slug?: string; // Przyjazny dla URL slug
  imageNames: string[]; // Nazwy plików obrazów produktu (patrz strona Images)
  rating: number; // Średnia ocena recenzji
  order: number; // Kolejność wyświetlania
  visibility: number; // 0=Publiczny, 1=Niewidoczny, 2=Prywatny
  storeId: string; // ID sklepu nadrzędnego
  variants: Variant[]; // Warianty produktu
  dateCreated: string; // Znacznik czasu ISO 8601
}

Warianty

Każdy produkt ma jeden lub więcej wariantów. Każdy wariant ma własną cenę, stan magazynowy i ustawienia:
interface Variant {
  id: string; // ID wariantu
  name: string; // Nazwa wariantu
  productId: string; // ID produktu nadrzędnego
  storeId: string; // ID sklepu
  cost: number; // Cena w walucie sklepu
  stock: number; // Dostępny stan magazynowy
  stockMode: number; // Tryb obliczania stanu (patrz poniżej)
  minimumQuantity: number; // Minimalna ilość zakupu (domyślnie: 1)
  maximumQuantity: number; // Maksymalna ilość zakupu (-1 = nieograniczona)
  order: number; // Kolejność wyświetlania
  imageNames: string[]; // Nazwy plików obrazów specyficznych dla wariantu
  type: number; // 0=Jednorazowy, 1=Subskrypcja
  subscriptionPeriod?: string; // Czas trwania subskrypcji jeśli dotyczy
  requireDiscordAuthorization: boolean;
  dateCreated: string;
}

Tryb obliczania stanu magazynowego

Pole stockMode określa sposób obliczania dostępności stanu:
WartośćTrybOpis
0ObliczonyStan jest automatycznie obliczany z dostępnych produktów
1IgnorowanyStan nie jest śledzony — zawsze dostępny
2StałyStan jest ustawiany ręcznie i dekrementowany przy zakupie
Zobacz enum Stock Calculation Mode po pełne szczegóły.

Wyświetlanie obrazów

imageNames produktów i wariantów zawierają nazwy plików, nie pełne adresy URL. Zobacz stronę Images, aby dowiedzieć się jak konstruować pełne adresy URL.

Wyświetlanie wariantów

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

  if (!productResponse.success) return;

  const product = productResponse.data;

  // Sortuj warianty według kolejności
  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(`  Stan: ${inStock ? "Dostępny" : "Brak w magazynie"}`);
    console.log(`  Min ilość: ${variant.minimumQuantity}`);
    console.log(
      `  Max ilość: ${
        variant.maximumQuantity === -1
          ? "Nieograniczona"
          : variant.maximumQuantity
      }`,
    );
  });
}

Wybór wariantu

<select id="variant-select" onchange="updatePrice()">
  <!-- Wypełniane dynamicznie -->
</select>
<span id="price"></span>
<button onclick="addToCart()">Dodaj do koszyka</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>

Recenzje produktu

Pobierz stronicowane recenzje dla produktu:
const response = await komerza.getProductReviews(productId, page);

Parametry

productId
string
wymagane
Unikalny ID produktu
page
number
wymagane
Numer strony (indeksowany od 1)

Zwraca

Zwraca PaginatedApiResponse<Review>:
interface PaginatedApiResponse<Review> {
  success: boolean;
  pages: number; // Łączna liczba stron
  data?: Review[]; // Tablica recenzji
  message?: string;
}

interface Review {
  id: string;
  rating: number; // 1-5 gwiazdek
  reason: string; // Tekst recenzji
  productId: string;
  reply?: string; // Odpowiedź sprzedawcy jeśli jest
  dateCreated: string;
}

Wyświetlanie recenzji

async function wyswietlRecenzje(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>Odpowiedź:</strong> ${review.reply}</p>`
          : ""
      }
      <time>${new Date(review.dateCreated).toLocaleDateString()}</time>
    </div>
  `,
    )
    .join("");

  // Paginacja
  if (response.pages > 1) {
    container.innerHTML += `
      <div class="pagination">
        ${
          page > 1
            ? `<button onclick="wyswietlRecenzje('${productId}', ${
                page - 1
              })">Poprzednia</button>`
            : ""
        }
        <span>Strona ${page} z ${response.pages}</span>
        ${
          page < response.pages
            ? `<button onclick="wyswietlRecenzje('${productId}', ${
                page + 1
              })">Następna</button>`
            : ""
        }
      </div>
    `;
  }
}

Obrazy produktu

Obrazy produktu są referencjonowane przez nazwę pliku. Skonstruuj pełny adres URL:
function getProductImageUrl(storeId, productId, imageName) {
  return `https://cdn.komerza.com/stores/${storeId}/products/${productId}/${imageName}`;
}

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

Galeria obrazów

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

  // Użyj obrazów wariantu jeśli dostępne, w przeciwnym razie obrazów produktu
  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("");
}

Obsługa stanu magazynowego

Sprawdź dostępność stanu przed dodaniem do koszyka:
function moznaAddacDoKoszyka(variant, quantity) {
  // stockMode 1 = Ignorowany (nieograniczony)
  if (variant.stockMode === 1) return true;

  // Sprawdź dostępny stan
  if (variant.stock < quantity) return false;

  // Sprawdź limity ilości
  if (quantity < variant.minimumQuantity) return false;
  if (variant.maximumQuantity !== -1 && quantity > variant.maximumQuantity)
    return false;

  return true;
}

function getStatusStanu(variant) {
  if (variant.stockMode === 1) return "Dostępny";
  if (variant.stock === 0) return "Brak w magazynie";
  if (variant.stock < 10) return `Tylko ${variant.stock} pozostało`;
  return "Dostępny";
}

Pełny przykład

<!DOCTYPE html>
<html>
  <head>
    <title>Strona produktu</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
          >Ilość: <input type="number" id="quantity" value="1" min="1"
        /></label>
        <button id="add-btn" onclick="addToCart()">Dodaj do koszyka</button>
      </div>

      <div class="reviews">
        <h2>Recenzje</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("Produkt nie znaleziony");
          return;
        }

        product = productResponse.data;
        formatter = fmt;

        // Wyświetl informacje o produkcie
        document.getElementById("name").textContent = product.name;
        document.getElementById("description").textContent =
          product.description;
        document.getElementById("rating").textContent =
          `Ocena: ${product.rating}★`;

        // Wyświetl obrazy
        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("");

        // Wypełnij warianty
        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,
        );

        // Status stanu
        let stockText = "Dostępny";
        if (variant.stockMode !== 1) {
          if (variant.stock === 0) stockText = "Brak w magazynie";
          else if (variant.stock < 10)
            stockText = `Tylko ${variant.stock} pozostało`;
        }
        document.getElementById("stock").textContent = stockText;

        // Zaktualizuj limity ilości
        const qtyInput = document.getElementById("quantity");
        qtyInput.min = variant.minimumQuantity;
        qtyInput.max =
          variant.maximumQuantity === -1 ? 999 : variant.maximumQuantity;
        qtyInput.value = variant.minimumQuantity;

        // Wyłącz przycisk jeśli brak w magazynie
        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("Dodano do koszyka!");
      }

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

        if (!response.success || response.data.length === 0) {
          document.getElementById("reviews").innerHTML = "<p>Brak recenzji</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>Odpowiedź: ${review.reply}</em></p>` : ""}
        </div>
      `,
          )
          .join("");
      }

      // Załaduj produkt z URL lub domyślny
      const urlParams = new URLSearchParams(window.location.search);
      const productId = urlParams.get("product") || "your-default-product-slug";
      loadProduct(productId);
    </script>
  </body>
</html>

Następne kroki

Formatowanie walut

Formatuj ceny w walucie sklepu

Zarządzanie koszykiem

Dodawaj produkty do koszyka