Add cart cleanup functionality to single page Bookable products

This commit is contained in:
Pedro Silva 2023-07-05 17:10:26 +01:00
parent c00b5906f7
commit 3b5a4b7f23
No known key found for this signature in database
GPG key ID: E2EE20C0669D24B3
5 changed files with 156 additions and 24 deletions

View file

@ -3,6 +3,8 @@ import BookingProduct from "../Entity/BookingProduct";
import onApprove from '../OnApproveHandler/onApproveForContinue';
import {payerData} from "../Helper/PayerData";
import {PaymentMethods} from "../Helper/CheckoutMethodState";
import CartJanitor from "../Helper/CartJanitor";
import FormHelper from "../Helper/FormHelper";
class SingleProductActionHandler {
@ -16,6 +18,7 @@ class SingleProductActionHandler {
this.updateCart = updateCart;
this.formElement = formElement;
this.errorHandler = errorHandler;
this.cartJanitor = null;
}
subscriptionsConfiguration() {
@ -74,29 +77,36 @@ class SingleProductActionHandler {
createOrder: this.createOrder(),
onApprove: onApprove(this, this.errorHandler),
onError: (error) => {
this.refreshMiniCart();
if (this.isBookingProduct() && error.message) {
this.errorHandler.clear();
this.errorHandler.message(error.message);
return;
}
this.errorHandler.genericError();
},
onCancel: () => {
// Could be used for every product type,
// but only clean the cart for Booking products for now.
if (this.isBookingProduct()) {
this.cleanCart();
} else {
this.refreshMiniCart();
}
}
}
}
createOrder()
{
this.cartJanitor = null;
let getProducts = (() => {
if ( this.isBookingProduct() ) {
return () => {
const getPrefixedFields = (formElement, prefix) => {
let fields = {};
for(const element of formElement.elements) {
if( element.name.startsWith(prefix) ) {
fields[element.name] = element.value;
}
}
return fields;
}
const id = document.querySelector('[name="add-to-cart"]').value;
return [new BookingProduct(id, 1, getPrefixedFields(this.formElement, "wc_bookings_field"))];
return [new BookingProduct(id, 1, FormHelper.getPrefixedFields(this.formElement, "wc_bookings_field"))];
}
} else if ( this.isGroupedProduct() ) {
return () => {
@ -129,6 +139,8 @@ class SingleProductActionHandler {
this.errorHandler.clear();
const onResolve = (purchase_units) => {
this.cartJanitor = (new CartJanitor()).addFromPurchaseUnits(purchase_units);
const payer = payerData();
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
this.config.bn_codes[this.config.context] : '';
@ -193,5 +205,17 @@ class SingleProductActionHandler {
return !!this.formElement.querySelector('.wc-booking-product-id');
}
cleanCart() {
this.cartJanitor.removeFromCart().then(() => {
this.refreshMiniCart();
}).catch(error => {
this.refreshMiniCart();
});
}
refreshMiniCart() {
jQuery(document.body).trigger('wc_fragment_refresh');
}
}
export default SingleProductActionHandler;

View file

@ -0,0 +1,65 @@
class CartJanitor {
constructor(cartItemKeys = [])
{
this.endpoint = wc_cart_fragments_params.wc_ajax_url.toString().replace('%%endpoint%%', 'remove_from_cart');
this.cartItemKeys = cartItemKeys;
}
addFromPurchaseUnits(purchaseUnits) {
for (const purchaseUnit of purchaseUnits || []) {
for (const item of purchaseUnit.items || []) {
if (!item.cart_item_key) {
continue;
}
this.cartItemKeys.push(item.cart_item_key);
}
}
return this;
}
removeFromCart()
{
return new Promise((resolve, reject) => {
if (!this.cartItemKeys || !this.cartItemKeys.length) {
resolve();
return;
}
const numRequests = this.cartItemKeys.length;
let numResponses = 0;
const tryToResolve = () => {
numResponses++;
if (numResponses >= numRequests) {
resolve();
}
}
for (const cartItemKey of this.cartItemKeys) {
const params = new URLSearchParams();
params.append('cart_item_key', cartItemKey);
if (!cartItemKey) {
tryToResolve();
continue;
}
fetch(this.endpoint, {
method: 'POST',
credentials: 'same-origin',
body: params
}).then(function (res) {
return res.json();
}).then(() => {
tryToResolve();
}).catch(() => {
tryToResolve();
});
}
});
}
}
export default CartJanitor;

View file

@ -0,0 +1,17 @@
/**
* Common Form utility methods
*/
export default class FormHelper {
static getPrefixedFields(formElement, prefix) {
let fields = {};
for(const element of formElement.elements) {
if( element.name.startsWith(prefix) ) {
fields[element.name] = element.value;
}
}
return fields;
}
}