xStore.customer

Dữ liệu riêng của khách đã đăng nhập. Module này chia thành sáu nhóm con: addresses, orders, points, coupons, savedProducts, productViews.

Phương thức

Phương thức Cú pháp Mô tả Từ phiên bản
addresses.list xStore.customer.addresses.list(): Promise<CursorPage<CustomerAddress>> Danh sách địa chỉ đã lưu. 1.0
addresses.create xStore.customer.addresses.create(address): Promise<CustomerAddress> Thêm địa chỉ mới. 1.0
addresses.update xStore.customer.addresses.update(id, address): Promise<CustomerAddress> Sửa một địa chỉ. 1.0
addresses.delete xStore.customer.addresses.delete(id): Promise<void> Xoá một địa chỉ. 1.0
addresses.setDefault xStore.customer.addresses.setDefault(id): Promise<void> Đặt một địa chỉ làm mặc định. 1.0
orders.list xStore.customer.orders.list({ cursor, limit }) hoặc xStore.customer.orders.list(cursor?, limit = 10): Promise<CursorPage<CustomerOrderListItem>> Danh sách đơn hàng của khách, phân trang bằng con trỏ. 1.0
orders.get xStore.customer.orders.get(orderId): Promise<OrderDetail> Chi tiết một đơn hàng. 1.0
points.get xStore.customer.points.get({ cursor, limit }) hoặc xStore.customer.points.get(cursor?, limit = 20): Promise<CustomerPointsRead> Số dư điểm thưởng và lịch sử biến động. 1.0
coupons.list xStore.customer.coupons.list({ cursor, limit }) hoặc xStore.customer.coupons.list(cursor?, limit = 20): Promise<CursorPage<CustomerCouponUsage>> Mã giảm giá khách đang có. 1.0
savedProducts.list xStore.customer.savedProducts.list({ cursor, limit }): Promise<CursorPage<SavedProduct>> Sản phẩm khách đã lưu. Mỗi dòng chỉ có id, product_id và created_at — KHÔNG kèm thẻ sản phẩm. Gom product_id lại rồi gọi products.list({ ids }) một lần, đừng gọi products.get() trong vòng lặp. 2.1
savedProducts.add xStore.customer.savedProducts.add(productId): Promise<void> Lưu một sản phẩm vào danh sách yêu thích. 2.1
savedProducts.remove xStore.customer.savedProducts.remove(productId): Promise<void> Bỏ một sản phẩm khỏi danh sách yêu thích. 2.1
productViews.list xStore.customer.productViews.list({ cursor, limit }): Promise<CursorPage<ProductView>> Lịch sử xem sản phẩm của CHÍNH khách đang đăng nhập, kèm view_count và last_viewed_at. Khác với recommendations.recentlyViewed(), vốn nhận diện khách vãng lai bằng sessionToken. 2.1
productViews.record xStore.customer.productViews.record(productId): Promise<void> Ghi nhận khách đã xem một sản phẩm. Cần đăng nhập; khách vãng lai dùng recommendations.recordView(). 2.1

Ví dụ đầy đủ

<script>
  // Module này chia thành sáu nhóm con: addresses, orders, points,
  // coupons, savedProducts, productViews.
  // Mọi hàm đều yêu cầu khách đã đăng nhập — bắt 401 và đưa về trang đăng nhập.
  async function renderAddresses() {
    try {
      const page = await xStore.customer.addresses.list();

      document.getElementById('addresses').innerHTML = page.items.map((a) => `
        <li>
          <strong>${a.recipient_name}</strong> — ${a.phone}<br>
          ${a.address_line}, ${a.ward}, ${a.district}, ${a.province}
          ${a.is_default ? '<em>(mặc định)</em>'
                         : `<button data-set-default="${a.id}">Đặt làm mặc định</button>`}
        </li>
      `).join('');
    } catch (err) {
      if (err.status === 401) {
        window.location.href = '/dang-nhap?next=' + encodeURIComponent(location.pathname);
      }
    }
  }

  document.getElementById('addresses').addEventListener('click', async (e) => {
    const id = e.target.dataset.setDefault;
    if (!id) return;

    await xStore.customer.addresses.setDefault(id);
    renderAddresses();
  });

  // Đơn hàng phân trang bằng con trỏ, không phải số trang.
  async function loadMoreOrders(cursor) {
    const page = await xStore.customer.orders.list({ cursor, limit: 10 });
    return { items: page.items, next: page.next_cursor };
  }

  // Sản phẩm đã lưu: danh sách chỉ trả về product_id, KHÔNG kèm thẻ sản
  // phẩm. Lấy id rồi hydrate một lần bằng products.list({ ids }).
  async function renderWishlist() {
    const luu = await xStore.customer.savedProducts.list({ limit: 50 });
    if (luu.items.length === 0) return;

    const the = await xStore.products.list({ ids: luu.items.map((s) => s.product_id) });

    document.getElementById('wishlist').innerHTML = the.items.map((p) => `
      <li>
        <a href="${p.url ?? '#'}">${p.title}</a>
        <span>${xStore.utils.formatCurrency(p.effective_price ?? p.price ?? 0)}</span>
        <button data-unsave="${p.id}">Bỏ lưu</button>
      </li>
    `).join('');
  }

  document.getElementById('wishlist').addEventListener('click', async (e) => {
    const id = e.target.dataset.unsave;
    if (!id) return;
    await xStore.customer.savedProducts.remove(id);
    renderWishlist();
  });

  renderAddresses();
  renderWishlist();
</script>

Thư viện gọi tới /api/... trên chính tên miền cửa hàng, nên không cần khai báo địa chỉ máy chủ ở bất kỳ đâu.

Xem thêm Sự kiện để giao diện tự cập nhật sau mỗi thao tác.