Công thức — Tài khoản & thanh toán

Đăng nhập

<form id="login-form">
  <input type="email"    name="email"    required>
  <input type="password" name="password" required>
  <button type="submit">Đăng nhập</button>
  <p id="login-error" class="error" hidden></p>
</form>

<script>
  document.getElementById('login-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const form = e.currentTarget;
    const err  = document.getElementById('login-error');
    err.hidden = true;

    try {
      await xStore.auth.login({
        email:    form.email.value,
        password: form.password.value,
      });
      // Tải lại để máy chủ dựng trang với biến customer đã có.
      window.location.href = new URLSearchParams(location.search).get('next') || '/tai-khoan';
    } catch (ex) {
      err.textContent = ex.message;
      err.hidden = false;
    }
  });
</script>

Vì sao phải tải lại trang? Biến customer trong Liquid được máy chủ dựng sẵn lúc trả HTML. Đăng nhập bằng JavaScript không làm HTML đã dựng thay đổi, nên sau khi đăng nhập cần điều hướng hoặc tải lại để phần giao diện phía máy chủ (tên khách trên header, khu vực tài khoản…) hiển thị đúng.

Nếu chỉ muốn cập nhật một phần giao diện mà không tải lại cả trang, dùng section động.

Đăng ký

<script>
  await xStore.auth.register({
    name:     'Nguyễn Văn A',
    email:    '[email protected]',
    password: '••••••••',
  });
</script>

Đăng ký thành công sẽ đăng nhập luôn và gộp giỏ hàng vãng lai vào tài khoản.

Kiểm tra trạng thái đăng nhập

<script>
  if (xStore.auth.isLoggedIn()) {
    const me = await xStore.auth.getMe();
    console.log(me.name);
  }
</script>

isLoggedIn() chỉ kiểm tra trình duyệt có phiên hay không — nhanh và đồng bộ. getMe() gọi máy chủ nên phản ánh đúng thực tế (phiên có thể đã hết hạn).

Đăng xuất

<script>
  xStore.auth.logout();          // đồng bộ, không cần await
  window.location.href = '/';
</script>

Sổ địa chỉ

Nhóm customer chia thành bốn nhóm con; địa chỉ nằm ở customer.addresses:

<script>
  const page = await xStore.customer.addresses.list();

  const created = await xStore.customer.addresses.create({
    full_name:    'Nguyễn Văn A',
    phone:        '0900000000',
    address_line: '12 Nguyễn Huệ',
    ward:         'Phường Bến Nghé',
    district:     'Quận 1',
    province:     'TP. Hồ Chí Minh',
  });

  await xStore.customer.addresses.setDefault(created.id);
  await xStore.customer.addresses.delete(created.id);
</script>

Tương tự: xStore.customer.orders.list(), xStore.customer.orders.get(id), xStore.customer.points.get(), xStore.customer.coupons.list().

Thanh toán — bốn bước, đúng thứ tự

Quy trình thanh toán bắt buộc theo thứ tự, vì mỗi bước kiểm tra kết quả của bước trước ở phía máy chủ: chưa có địa chỉ thì không tính được phí vận chuyển, chưa chọn vận chuyển thì không chốt được số tiền phải trả.

<script>
  async function datHang(form) {
    // Bước 1 — mở phiên thanh toán từ giỏ hàng hiện tại.
    const cartToken = xStore.cart.getToken();
    let session = await xStore.checkout.start(cartToken);

    // Bước 2 — địa chỉ giao hàng.
    session = await xStore.checkout.setAddress(session.id, {
      full_name:    form.full_name.value,
      phone:        form.phone.value,
      address_line: form.address_line.value,
      ward:         form.ward.value,
      district:     form.district.value,
      province:     form.province.value,
    });

    // Bước 3 — phương thức vận chuyển (danh sách phụ thuộc địa chỉ ở bước 2).
    session = await xStore.checkout.setShipping(session.id, {
      shipping_method_id: form.shipping_method.value,
    });

    // Bước 4 — khởi tạo thanh toán và tạo đơn hàng.
    session = await xStore.checkout.initiatePayment(session.id, {
      payment_method: form.payment_method.value,
    });

    return session;
  }

  document.getElementById('checkout-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const btn = e.currentTarget.querySelector('[type=submit]');
    btn.disabled = true;
    try {
      const session = await datHang(e.currentTarget);
      // Cổng thanh toán online sẽ trả về địa chỉ chuyển hướng.
      window.location.href = session.payment_redirect_url || '/tai-khoan/don-hang';
    } catch (err) {
      alert(err.message);
      btn.disabled = false;
    }
  });
</script>

Luôn khoá nút gửi trong lúc chờ — bấm hai lần có thể tạo hai đơn hàng.

Trang checkout không có biến customer và menus (xem Biến toàn cục), nên nếu cần tên khách trên trang này, hãy lấy bằng xStore.auth.getMe().