Nhảy tới nội dung

Xây dựng Shopping Template cùng Tini App (Phần 3)

· Một phút để đọc

🏁 Recap

phần 1phần 2, chúng ta đã cùng nhau tìm hiểu về Shopping Template và "thực chiến" với 2 pages: HomeSearch. Ở phần này, mình sẽ cùng các bạn tiếp tục xây dựng giỏ hàng và thực hiện mock payment.

Mục lục

I. Quản lý state trong Tini App

II. Xây dựng giỏ hàng

  1. Navigate đến giỏ hàng
  2. Thêm sản phầm vào giỏ hàng
  3. Sửa số lượng sản phẩm
  4. Xoá sản phầm khỏi giỏ hàng
  5. Thêm + xoá coupon
  6. Tạo payment (Mở rộng)

III. Tổng kết


I. Quản lý state trong Tini App

  • Mình đã có một bài viết nói về cách tiếp cận và xử lý state trong Tini App. Bạn có thể đọc bài viết Quản lý state trong Tini App - Cái nhìn tổng quan và cách tiếp cận Phần 1Phần 2.
  • Ý tưởng chung ở đây chúng ta sẽ dùng app như một global store - nơi mà mọi page và component đều có thể truy cập tới bằng method getApp().
  • Kết hợp Event Emitter để thực hiện render khi app thay đổi.

📌 Xem thêm getApp()

app.js
App({
cartEvent: new EventEmitter(),

cart: {
buyer: {},
seller: {},
orderedProducts: [],
productId: '',
shippingFee: 0,
price: 0,
total: 0,
coupon: {
name: '',
discount: 0,
isValid: false,
},
},

// ...
});

II. Xây dựng giỏ hàng

Cart Page

Như video demo ở trên, ở Cart Page chúng ta sẽ có các actions:

  1. Navigate đến giỏ hàng
  2. Thêm sản phầm vào giỏ hàng
  3. Sửa số lượng sản phẩm
  4. Xoá sản phẩm khỏi giỏ hàng
  5. Thêm + xoá coupon
  6. Tạo payment (Mở rộng)

Hãy cùng đi từng action nào

1. Navigate đến giỏ hàng

Để navigate đến giỏ hàng, ta sẽ sử dụng jsapi my.navigateTo()

pages/detail/index.js
navigateToCart () {
my.navigateTo({ url: `pages/cart/index` });
};

📌 Xem thêm my.navigateTo()

Tuy nhiên, để gắn sự kiện cho icon ở navigation bar, chúng ta phải khai báo trong event onCustomIconEvent

pages/detail/index.js
onCustomIconEvent(e) {
navigateToCart();
},

📌 Xem thêm onCustomIconEvent()

  • Mỗi khi sử dụng my.navigateTo(), framework sẽ push page đó vào screen stack.
  • Để pop screen ra khỏi stack, ta có thể bấm vào nút back trên navigation bar hoặc sử dụng jsapi my.navigateBack()

📌 Xem thêm my.navigateBack()

2. Thêm sản phẩm vào giỏ hàng

Khi tap vào button Add to cart, chúng ta sẽ gọi addProduct() từ app để add sản phầm vào giỏ hàng

pages/detail/index.js
addToCart() {
getApp().addProduct(this.data.product);
},

Ta sẽ implement addProduct() ở app như sau:

  • Tìm kiếm xem ở giỏ hàng đã có sản phẩm đó chưa.
  • Nếu chưa có thì add vào và cho số lượng là 1.
  • Nếu có rồi thì tăng số lượng lên 1 đơn vị.
  • Tính toán lại giá bằng cách gọi calculatePrices() - Hàm này sẽ tính toán lại giá và emit event CART_UPDATE.
app.js
addProduct(product) {
const position = this.cart.orderedProducts.findIndex(
(item) => item.id === product.id,
);
if (position !== -1) this.cart.orderedProducts[position].quantity += 1;
else this.cart.orderedProducts.push({ ...product, quantity: 1 });

this.calculatePrices();
},
calculatePrices() {
const { shippingFee, coupon, orderedProducts } = this.cart;
const price = orderedProducts.reduce((acc, curr) => {
return acc + curr.price * curr.quantity;
}, 0);
const total = price > 0 ? price + shippingFee - coupon.discount : 0;
this.cart = {
...this.cart,
price,
total,
};

this.cartEvent.emit(EMITTERS.CART_UPDATE, this.cart);
},

pages/cart, ta sẽ lắng nghe event CART_UPDATE được emit ở trên và update data cart mới từ đó render lại thông tin cart

pages/cart/index.js
async onLoad() {
this.disposableCollection.push(
app.cartEvent.on(EMITTERS.CART_UPDATE, (cart) =>
this.setData({
cart,
}),
),
);
},
cart

3. Sửa số lượng sản phẩm

Khi tap button + hoặc - hoặc nhập trực tiếp số vào component stepper, ta sẽ gọi changeQuantityProduct() của app

📌 Xem thêm stepper

pages/detail/index.js
onChangeQuantityProduct(product, quantity) {
getApp().changeQuantityProduct(product, quantity);
},

Ta sẽ implement changeQuantityProduct() ở app như sau:

  • Tìm sản phẩm trong cart.
  • Update lại số lượng theo số lượng trong param nhận được.
  • Tính toán lại giá bằng cách gọi calculatePrices() tương tự như trên.
app.js
changeQuantityProduct(product, quantity) {
const position = this.cart.orderedProducts.findIndex(
(item) => item.id === product.id,
);
if (position !== -1) {
this.cart.orderedProducts[position].quantity = quantity;
}

this.calculatePrices();
},

4. Xoá sản phầm khỏi giỏ hàng

Khi tap vào icon close, chúng ta sẽ lưu sản phẩm được chọn lại (vì trong cart có thể sẽ có nhiều sản phẩm) và show modal xác nhận

modal confirm

📌 Xem thêm modal

components/order-list/index.js
confirmRemoveOrder(product) {
this.selectedProduct = product;
this.setData({
modal: {
isShow: true,
headers: ['Confirmation'],
descriptions: ['Do you want to remove this product from your cart?'],
leftButton: 'Yes',
rightButton: 'No',
},
});
},

Khi tap vào Yes, removeProduct() ở app sẽ được gọi và nhận vào product được chọn mà ta đã lưu lại ở trên.

onRemoveProduct(product) {
app.removeProduct(product);
},

Ta sẽ implement removeProduct() ở app như sau:

  • Tìm sản phẩm trong cart.
  • Remove sản phẩm khỏi cart.
  • Tính toán lại giá bằng cách gọi calculatePrices() tương tự như trên.
app.js
removeProduct(product) {
const position = this.cart.orderedProducts.findIndex(
(item) => item.id === product.id,
);
if (position !== -1) this.cart.orderedProducts.splice(position, 1);

this.calculatePrices();
},

5. Thêm + xoá coupon

Tương tự như trên, ta cũng implement selectCoupon()removeCoupon() trong app. Sau đó calculatePrices() cũng sẽ được gọi để tính toán lại giá thành và trigger event update UI của cart.

coupon
async selectCoupon(code) {
try {
const coupon = await getCouponFromCodeAPI(code);
this.cart.coupon = coupon;

this.calculatePrices();
} catch {}
},

removeCoupon() {
this.cart.coupon = {
name: '',
discount: 0,
isValid: false,
};

this.calculatePrices();
},

6. Tạo payment (Mở rộng)

Bạn có thể để tạo payment thông qua hệ thống payment của Tiki thông qua jsapi my.makePayment().

📌 Xem thêm my.makePayment()


🔚 III. Tổng kết

Một lần nữa, cảm ơn các bạn đã đọc cuối bài, qua 3 phần của blog Xây dựng Shopping Template cùng Tini App chúng ta đã tìm hiểu cách cài đặt 3 pages lớn nhất của template là Home Page, Search Page, Cart Page đồng thời biết được data flows của một ứng dụng Tini Apps.

Vì thời gian có hạn nên các ví dụ ở bài blog này có thể chưa đầy đủ vì thế mình có đính kèm link github ở đây, bạn có thể clone về và ngâm cứu sâu hơn.

Hi vọng vài viết sẽ giúp ích cho bạn trong quá trình tìm hiểu và xây dựng ứng dụng trên nền tảng Tini App 🎉