Skip to content

holoAddToCart - UNAS Webshop Integration

Overview

The holoAddToCart function allows adding products directly to the UNAS webshop cart from HoloStep 3D configurators using a URL parameter.

Usage

Products are added to the cart via URL parameter:

text
https://webshop.com/product?holoAddToCart=SKU1:2,SKU2:1

Supported Formats

FormatExampleDescription
Single SKUholoAddToCart=SKU1Add 1 item
SKU with quantityholoAddToCart=SKU1:2Add 2 items
Multiple productsholoAddToCart=SKU1:2,SKU2:1,SKU3:5Multiple products at once

Flow

  1. On page load, the initUnas() function runs
  2. Reads the holoAddToCart URL parameter
  3. Parses the parameter into SKU and quantity pairs
  4. Calls UnasCartAdapter.add() for each product
  5. UNAS AJAX API call (/shop_ajax/ajax_cart.php)
  6. Removes URL parameter (to prevent duplicate additions)
  7. Refreshes cart UI (cart_refresh() or page reload)

Main Components

1. initUnas() - Entry Point

typescript
export function initUnas() {
  const urlParams = new URLSearchParams(window.location.search);
  const holoAddToCartParam = urlParams.get('holoAddToCart');
  
  // Handle holo actions when the page loads
  handleHoloActions();
}

2. parseHoloAddToCart() - Parameter Parsing

typescript
const parseHoloAddToCart = (param: string): Array<{ sku: string; qty: number }> => {
  if (!param) return [];

  return param
    .split(',')
    .map((item) => {
      const [sku, qtyStr] = item.trim().split(':');
      const qty = qtyStr ? parseInt(qtyStr, 10) : 1;
      const validQty = isNaN(qty) || qty <= 0 ? 1 : qty;
      return { sku: sku.trim(), qty: validQty };
    })
    .filter((item) => item.sku);
};

3. handleHoloActions() - Add to Cart Logic

typescript
const handleHoloActions = async () => {
  if (holoAddToCartParam) {
    const cartItems = parseHoloAddToCart(holoAddToCartParam);

    if (cartItems.length === 0) {
      console.warn('No valid SKUs found in holoAddToCart parameter:', holoAddToCartParam);
      return;
    }

    const cartAdapter = new UnasCartAdapter();

    for (const { sku, qty } of cartItems) {
      try {
        await cartAdapter.add(sku, qty);
      } catch (error: any) {
        console.error(`Failed to add ${sku} (qty: ${qty}) to cart:`, error);
      }
    }

    // Remove URL parameter
    urlParams.delete('holoAddToCart');
    const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '');
    window.history.replaceState({}, '', newUrl);

    // Refresh cart
    if (window.location.pathname.includes('/shop_cart.php')) {
      window.location.reload();
    } else if (typeof window.cart_refresh === 'function') {
      window.cart_refresh();
    }
  }
};

UnasCartAdapter

Constants and Helper Functions

typescript
const CART_URI = '/shop_ajax/api.php';
const ADD_2_CART_URI = '/shop_ajax/ajax_cart.php';

function requireApiAuth() {
  const apiAuth = window?.UNAS?.api_auth;
  if (!apiAuth) {
    throw new Error('[UNAS CartAdapter] window.UNAS.api_auth is missing');
  }
  return apiAuth;
}

function buildForm(data) {
  const fd = new FormData();
  Object.entries(data).forEach(([k, v]) => fd.append(k, v));
  return fd;
}

add() - Add Product

typescript
async add(sku, qty = 1) {
  const api_auth = requireApiAuth();

  const body = buildForm({
    get_ajax: 1,
    result_type: 'json',
    lang_master: 'hu',
    action: 'add',
    sku,
    qty,
    api_auth,
  });

  const res = await fetch(ADD_2_CART_URI, {
    method: 'POST',
    body,
    credentials: 'same-origin',
  });

  if (!res.ok) throw new Error(`[UNAS add] HTTP ${res.status}`);
  return await res.json();
}

remove() - Remove Product

typescript
async remove(selector: any = {}) {
  const api_auth = requireApiAuth();
  const { id, sku } = selector;

  // Strategy A: delete by id or sku
  try {
    const delKey = id != null ? { id } : sku ? { sku } : null;
    if (delKey) {
      const delBody = buildForm({
        get_ajax: 1,
        result_type: 'json',
        lang_master: 'hu',
        action: 'del',
        ...delKey,
        api_auth,
      });

      const delRes = await fetch(ADD_2_CART_URI, {
        method: 'POST',
        body: delBody,
        credentials: 'same-origin',
      });

      if (delRes.ok) {
        return await delRes.json().catch(() => ({}));
      }
    }
  } catch { /* fall through to Strategy B */ }

  // Strategy B: set qty=0
  if (sku) {
    const zeroBody = buildForm({
      get_ajax: 1,
      result_type: 'json',
      lang_master: 'hu',
      action: 'add',
      sku,
      qty: 0,
      api_auth,
    });

    const zeroRes = await fetch(ADD_2_CART_URI, {
      method: 'POST',
      body: zeroBody,
      credentials: 'same-origin',
    });

    if (!zeroRes.ok) throw new Error(`[UNAS remove] HTTP ${zeroRes.status}`);
    return await zeroRes.json();
  }

  throw new Error('[UNAS remove] Provide id or sku');
}

getCart() - Get Cart

typescript
async getCart() {
  const api_auth = requireApiAuth();

  const params = new URLSearchParams({
    get_ajax: 1,
    action: 'getCart',
    api_auth,
  } as any);

  const res = await fetch(`${CART_URI}?${params.toString()}`, {
    method: 'GET',
    credentials: 'same-origin',
  });

  if (!res.ok) throw new Error(`[UNAS getCart] HTTP ${res.status}`);
  const result = await res.json();

  const rawItems = Array.isArray(result?.items) ? result.items : [];
  const valid = rawItems.map(mapCartItem).filter(Boolean);
  const { itemCount, totalPrice } = summarizeCart(result, valid);

  return { items: valid, itemCount, totalPrice, raw: result };
}

UNAS Global Object

The window.UNAS object is required for the integration to work.

typescript
interface UnasShop {
  base_url: string;
  domain: string;
  username: string;
  id: number;
  lang: string;
  currency_type: string;
  currency_code: string;
  sku: string;
  product_id: string;
}

interface Window {
  UNAS?: {
    api_auth: string;  // Required for API calls!
    onAddToCart: (callback: (event: any, product: UnasProduct) => void) => void;
    onRemoveFromCart: (callback: (event: any, product: UnasProduct) => void) => void;
    getCart: (callback: (unasCart: UnasCartItem) => void) => void;
    shop: UnasShop;
  };
}

API Endpoint Summary

OperationEndpointMethodAction
Add/shop_ajax/ajax_cart.phpPOSTadd
Remove/shop_ajax/ajax_cart.phpPOSTdel
Get Cart/shop_ajax/api.phpGETgetCart

Required Parameters for All Calls

  • api_auth - value of window.UNAS.api_auth
  • get_ajax: 1
  • result_type: 'json'

Example Usage

typescript
import { UnasCartAdapter } from '@holo/util';

const adapter = new UnasCartAdapter();

// Add product
await adapter.add('LBIVENGR4', 2);

// Remove product by SKU
await adapter.remove({ sku: 'LBIVENGR4' });

// Remove product by ID
await adapter.remove({ id: 12345 });

// Get cart
const cart = await adapter.getCart();
// Return value:
// {
//   items: [{ id: '123', name: 'Product', quantity: 2, price: 5000, sku: 'SKU1' }],
//   itemCount: 2,
//   totalPrice: 10000,
//   raw: { /* original UNAS response */ }
// }