2020-02-25 11:36:53 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
import type {
|
|
|
|
Cart,
|
|
|
|
CartResponse,
|
|
|
|
CartResponseItem,
|
2021-06-07 09:16:47 +00:00
|
|
|
ExtensionCartUpdateArgs,
|
2021-11-16 12:39:43 +00:00
|
|
|
BillingAddressShippingAddress,
|
2021-02-24 01:36:24 +00:00
|
|
|
} from '@woocommerce/types';
|
|
|
|
import { camelCase, mapKeys } from 'lodash';
|
2021-09-21 13:25:44 +00:00
|
|
|
import type { AddToCartEventDetail } from '@woocommerce/type-defs/events';
|
2022-02-22 17:45:01 +00:00
|
|
|
import { BillingAddress, ShippingAddress } from '@woocommerce/settings';
|
2022-03-10 13:22:05 +00:00
|
|
|
import { controls } from '@wordpress/data';
|
2020-02-25 11:36:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { ACTION_TYPES as types } from './action-types';
|
2020-03-09 02:09:47 +00:00
|
|
|
import { STORE_KEY as CART_STORE_KEY } from './constants';
|
2020-03-19 11:50:51 +00:00
|
|
|
import { apiFetchWithHeaders } from '../shared-controls';
|
2021-02-24 01:36:24 +00:00
|
|
|
import type { ResponseError } from '../types';
|
2021-12-07 15:47:50 +00:00
|
|
|
import { ReturnOrGeneratorYieldUnion } from '../mapped-types';
|
2020-02-25 11:36:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an action object used in updating the store with the provided items
|
|
|
|
* retrieved from a request using the given querystring.
|
|
|
|
*
|
|
|
|
* This is a generic response action.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {CartResponse} response
|
2020-02-25 11:36:53 +00:00
|
|
|
*/
|
2021-05-16 17:59:32 +00:00
|
|
|
export const receiveCart = (
|
|
|
|
response: CartResponse
|
|
|
|
): { type: string; response: Cart } => {
|
2022-06-15 09:56:52 +00:00
|
|
|
const cart = mapKeys( response, ( _, key ) =>
|
2021-02-24 01:36:24 +00:00
|
|
|
camelCase( key )
|
2022-06-15 09:56:52 +00:00
|
|
|
) as unknown as Cart;
|
2020-02-25 11:36:53 +00:00
|
|
|
return {
|
|
|
|
type: types.RECEIVE_CART,
|
2021-02-24 01:36:24 +00:00
|
|
|
response: cart,
|
2021-05-16 17:59:32 +00:00
|
|
|
};
|
2021-03-01 17:47:22 +00:00
|
|
|
};
|
2020-02-25 11:36:53 +00:00
|
|
|
|
2022-02-22 17:45:01 +00:00
|
|
|
/**
|
|
|
|
* Returns an action object used in updating the store with the provided cart.
|
|
|
|
*
|
|
|
|
* This omits the customer addresses so that only updates to cart items and totals are received. This is useful when
|
|
|
|
* currently editing address information to prevent it being overwritten from the server.
|
|
|
|
*
|
|
|
|
* This is a generic response action.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {CartResponse} response
|
2022-02-22 17:45:01 +00:00
|
|
|
*/
|
|
|
|
export const receiveCartContents = (
|
|
|
|
response: CartResponse
|
|
|
|
): { type: string; response: Partial< Cart > } => {
|
2022-06-15 09:56:52 +00:00
|
|
|
const cart = mapKeys( response, ( _, key ) =>
|
2022-02-22 17:45:01 +00:00
|
|
|
camelCase( key )
|
2022-06-15 09:56:52 +00:00
|
|
|
) as unknown as Cart;
|
2022-02-22 17:45:01 +00:00
|
|
|
const { shippingAddress, billingAddress, ...cartWithoutAddress } = cart;
|
|
|
|
return {
|
|
|
|
type: types.RECEIVE_CART,
|
|
|
|
response: cartWithoutAddress,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-02-25 11:36:53 +00:00
|
|
|
/**
|
2021-02-24 01:36:24 +00:00
|
|
|
* Returns an action object used for receiving customer facing errors from the API.
|
2020-02-25 11:36:53 +00:00
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {ResponseError|null} [error=null] An error object containing the error
|
|
|
|
* message and response code.
|
|
|
|
* @param {boolean} [replace=true] Should existing errors be replaced,
|
|
|
|
* or should the error be appended.
|
2020-02-25 11:36:53 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const receiveError = (
|
2021-02-24 01:36:24 +00:00
|
|
|
error: ResponseError | null = null,
|
|
|
|
replace = true
|
2021-03-01 17:47:22 +00:00
|
|
|
) =>
|
|
|
|
( {
|
2020-02-25 11:36:53 +00:00
|
|
|
type: replace ? types.REPLACE_ERRORS : types.RECEIVE_ERROR,
|
|
|
|
error,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2020-02-25 11:36:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an action object used to track when a coupon is applying.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {string} [couponCode] Coupon being added.
|
2020-02-25 11:36:53 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const receiveApplyingCoupon = ( couponCode: string ) =>
|
|
|
|
( {
|
2020-02-25 11:36:53 +00:00
|
|
|
type: types.APPLYING_COUPON,
|
|
|
|
couponCode,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2020-02-25 11:36:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an action object used to track when a coupon is removing.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {string} [couponCode] Coupon being removed..
|
2020-02-25 11:36:53 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const receiveRemovingCoupon = ( couponCode: string ) =>
|
|
|
|
( {
|
2020-02-25 11:36:53 +00:00
|
|
|
type: types.REMOVING_COUPON,
|
|
|
|
couponCode,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2020-02-25 11:36:53 +00:00
|
|
|
|
2020-03-19 11:50:51 +00:00
|
|
|
/**
|
|
|
|
* Returns an action object for updating a single cart item in the store.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {CartResponseItem} [response=null] A cart item API response.
|
2020-03-19 11:50:51 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const receiveCartItem = ( response: CartResponseItem | null = null ) =>
|
|
|
|
( {
|
2020-03-19 11:50:51 +00:00
|
|
|
type: types.RECEIVE_CART_ITEM,
|
|
|
|
cartItem: response,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2020-03-19 11:50:51 +00:00
|
|
|
|
|
|
|
/**
|
2021-02-24 01:36:24 +00:00
|
|
|
* Returns an action object to indicate if the specified cart item quantity is
|
|
|
|
* being updated.
|
2020-03-19 11:50:51 +00:00
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {string} cartItemKey Cart item being updated.
|
|
|
|
* @param {boolean} [isPendingQuantity=true] Flag for update state; true if API
|
|
|
|
* request is pending.
|
2020-03-19 11:50:51 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const itemIsPendingQuantity = (
|
2021-02-24 01:36:24 +00:00
|
|
|
cartItemKey: string,
|
|
|
|
isPendingQuantity = true
|
2021-03-01 17:47:22 +00:00
|
|
|
) =>
|
|
|
|
( {
|
2020-04-07 11:03:22 +00:00
|
|
|
type: types.ITEM_PENDING_QUANTITY,
|
2020-03-19 11:50:51 +00:00
|
|
|
cartItemKey,
|
2020-04-07 11:03:22 +00:00
|
|
|
isPendingQuantity,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2020-03-19 11:50:51 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an action object to remove a cart item from the store.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {string} cartItemKey Cart item to remove.
|
|
|
|
* @param {boolean} [isPendingDelete=true] Flag for update state; true if API
|
|
|
|
* request is pending.
|
2020-03-19 11:50:51 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const itemIsPendingDelete = (
|
2021-02-24 01:36:24 +00:00
|
|
|
cartItemKey: string,
|
|
|
|
isPendingDelete = true
|
2021-03-01 17:47:22 +00:00
|
|
|
) =>
|
|
|
|
( {
|
2020-03-19 11:50:51 +00:00
|
|
|
type: types.RECEIVE_REMOVED_ITEM,
|
|
|
|
cartItemKey,
|
2020-04-07 11:03:22 +00:00
|
|
|
isPendingDelete,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2021-03-24 13:28:11 +00:00
|
|
|
/**
|
|
|
|
* Returns an action object to mark the cart data in the store as stale.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {boolean} [isCartDataStale=true] Flag to mark cart data as stale; true if
|
|
|
|
* lastCartUpdate timestamp is newer than the
|
|
|
|
* one in wcSettings.
|
2021-03-24 13:28:11 +00:00
|
|
|
*/
|
|
|
|
export const setIsCartDataStale = ( isCartDataStale = true ) =>
|
|
|
|
( {
|
|
|
|
type: types.SET_IS_CART_DATA_STALE,
|
|
|
|
isCartDataStale,
|
|
|
|
} as const );
|
2020-03-19 11:50:51 +00:00
|
|
|
|
|
|
|
/**
|
2021-02-24 01:36:24 +00:00
|
|
|
* Returns an action object used to track when customer data is being updated
|
|
|
|
* (billing and/or shipping).
|
2020-03-19 11:50:51 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const updatingCustomerData = ( isResolving: boolean ) =>
|
|
|
|
( {
|
2020-11-20 15:13:35 +00:00
|
|
|
type: types.UPDATING_CUSTOMER_DATA,
|
2020-03-19 11:50:51 +00:00
|
|
|
isResolving,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2020-03-19 11:50:51 +00:00
|
|
|
|
2020-03-31 15:40:27 +00:00
|
|
|
/**
|
|
|
|
* Returns an action object used to track whether the shipping rate is being
|
|
|
|
* selected or not.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {boolean} isResolving True if shipping rate is being selected.
|
2020-03-31 15:40:27 +00:00
|
|
|
*/
|
2021-03-01 17:47:22 +00:00
|
|
|
export const shippingRatesBeingSelected = ( isResolving: boolean ) =>
|
|
|
|
( {
|
2020-03-31 15:40:27 +00:00
|
|
|
type: types.UPDATING_SELECTED_SHIPPING_RATE,
|
|
|
|
isResolving,
|
2021-03-01 17:47:22 +00:00
|
|
|
} as const );
|
2020-03-31 15:40:27 +00:00
|
|
|
|
2021-09-21 13:25:44 +00:00
|
|
|
/**
|
|
|
|
* Triggers an adding to cart event so other blocks can update accordingly.
|
|
|
|
*/
|
|
|
|
export const triggerAddingToCartEvent = () =>
|
|
|
|
( {
|
|
|
|
type: types.TRIGGER_ADDING_TO_CART_EVENT,
|
|
|
|
} as const );
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Triggers an added to cart event so other blocks can update accordingly.
|
|
|
|
*/
|
|
|
|
export const triggerAddedToCartEvent = ( {
|
|
|
|
preserveCartData,
|
|
|
|
}: AddToCartEventDetail ) =>
|
|
|
|
( {
|
|
|
|
type: types.TRIGGER_ADDED_TO_CART_EVENT,
|
|
|
|
preserveCartData,
|
|
|
|
} as const );
|
|
|
|
|
2021-06-07 09:16:47 +00:00
|
|
|
/**
|
|
|
|
* POSTs to the /cart/extensions endpoint with the data supplied by the extension.
|
|
|
|
*
|
|
|
|
* @param {Object} args The data to be posted to the endpoint
|
|
|
|
*/
|
|
|
|
export function* applyExtensionCartUpdate(
|
|
|
|
args: ExtensionCartUpdateArgs
|
|
|
|
): Generator< unknown, CartResponse, { response: CartResponse } > {
|
|
|
|
try {
|
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: '/wc/store/v1/cart/extensions',
|
2021-06-07 09:16:47 +00:00
|
|
|
method: 'POST',
|
|
|
|
data: { namespace: args.namespace, data: args.data },
|
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
yield receiveCart( response );
|
|
|
|
return response;
|
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-throw the error.
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-25 11:36:53 +00:00
|
|
|
/**
|
|
|
|
* Applies a coupon code and either invalidates caches, or receives an error if
|
|
|
|
* the coupon cannot be applied.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {string} couponCode The coupon code to apply to the cart.
|
2021-02-24 01:36:24 +00:00
|
|
|
* @throws Will throw an error if there is an API problem.
|
2020-02-25 11:36:53 +00:00
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
export function* applyCoupon(
|
|
|
|
couponCode: string
|
|
|
|
): Generator< unknown, boolean, { response: CartResponse } > {
|
2020-02-25 11:36:53 +00:00
|
|
|
yield receiveApplyingCoupon( couponCode );
|
|
|
|
|
|
|
|
try {
|
2020-03-19 11:50:51 +00:00
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: '/wc/store/v1/cart/apply-coupon',
|
2020-02-25 11:36:53 +00:00
|
|
|
method: 'POST',
|
2020-02-26 11:46:58 +00:00
|
|
|
data: {
|
|
|
|
code: couponCode,
|
|
|
|
},
|
2020-02-25 11:36:53 +00:00
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
|
2020-03-19 11:50:51 +00:00
|
|
|
yield receiveCart( response );
|
2020-03-03 10:26:02 +00:00
|
|
|
yield receiveApplyingCoupon( '' );
|
2020-02-25 11:36:53 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
2020-04-09 12:52:31 +00:00
|
|
|
yield receiveApplyingCoupon( '' );
|
|
|
|
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
|
|
|
|
2020-03-03 10:26:02 +00:00
|
|
|
// Re-throw the error.
|
|
|
|
throw error;
|
2020-02-25 11:36:53 +00:00
|
|
|
}
|
|
|
|
|
2020-03-03 10:26:02 +00:00
|
|
|
return true;
|
2020-02-25 11:36:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes a coupon code and either invalidates caches, or receives an error if
|
|
|
|
* the coupon cannot be removed.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {string} couponCode The coupon code to remove from the cart.
|
2021-02-24 01:36:24 +00:00
|
|
|
* @throws Will throw an error if there is an API problem.
|
2020-02-25 11:36:53 +00:00
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
export function* removeCoupon(
|
|
|
|
couponCode: string
|
|
|
|
): Generator< unknown, boolean, { response: CartResponse } > {
|
2020-02-25 11:36:53 +00:00
|
|
|
yield receiveRemovingCoupon( couponCode );
|
|
|
|
|
|
|
|
try {
|
2020-03-19 11:50:51 +00:00
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: '/wc/store/v1/cart/remove-coupon',
|
2020-02-25 11:36:53 +00:00
|
|
|
method: 'POST',
|
2020-02-26 11:46:58 +00:00
|
|
|
data: {
|
|
|
|
code: couponCode,
|
|
|
|
},
|
2020-02-25 11:36:53 +00:00
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
|
2020-03-19 11:50:51 +00:00
|
|
|
yield receiveCart( response );
|
2020-03-03 10:26:02 +00:00
|
|
|
yield receiveRemovingCoupon( '' );
|
2020-02-25 11:36:53 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
2020-03-03 10:26:02 +00:00
|
|
|
yield receiveRemovingCoupon( '' );
|
2020-04-09 12:52:31 +00:00
|
|
|
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
|
|
|
|
2020-03-03 10:26:02 +00:00
|
|
|
// Re-throw the error.
|
|
|
|
throw error;
|
2020-02-25 11:36:53 +00:00
|
|
|
}
|
|
|
|
|
2020-03-03 10:26:02 +00:00
|
|
|
return true;
|
2020-02-25 11:36:53 +00:00
|
|
|
}
|
2020-02-28 02:05:10 +00:00
|
|
|
|
2020-04-06 10:36:28 +00:00
|
|
|
/**
|
|
|
|
* Adds an item to the cart:
|
|
|
|
* - Calls API to add item.
|
|
|
|
* - If successful, yields action to add item from store.
|
|
|
|
* - If error, yields action to store error.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {number} productId Product ID to add to cart.
|
|
|
|
* @param {number} [quantity=1] Number of product ID being added to cart.
|
2021-02-24 01:36:24 +00:00
|
|
|
* @throws Will throw an error if there is an API problem.
|
2020-04-06 10:36:28 +00:00
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
export function* addItemToCart(
|
|
|
|
productId: number,
|
|
|
|
quantity = 1
|
|
|
|
): Generator< unknown, void, { response: CartResponse } > {
|
2020-04-06 10:36:28 +00:00
|
|
|
try {
|
2021-09-21 13:25:44 +00:00
|
|
|
yield triggerAddingToCartEvent();
|
2020-04-06 10:36:28 +00:00
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: `/wc/store/v1/cart/add-item`,
|
2020-04-06 10:36:28 +00:00
|
|
|
method: 'POST',
|
|
|
|
data: {
|
|
|
|
id: productId,
|
|
|
|
quantity,
|
|
|
|
},
|
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
|
|
|
|
yield receiveCart( response );
|
2021-09-21 13:25:44 +00:00
|
|
|
yield triggerAddedToCartEvent( { preserveCartData: true } );
|
2020-04-06 10:36:28 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
2020-04-09 12:52:31 +00:00
|
|
|
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
2020-04-27 16:24:54 +00:00
|
|
|
|
|
|
|
// Re-throw the error.
|
|
|
|
throw error;
|
2020-04-06 10:36:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-28 02:05:10 +00:00
|
|
|
/**
|
|
|
|
* Removes specified item from the cart:
|
|
|
|
* - Calls API to remove item.
|
|
|
|
* - If successful, yields action to remove item from store.
|
|
|
|
* - If error, yields action to store error.
|
|
|
|
* - Sets cart item as pending while API request is in progress.
|
|
|
|
*
|
|
|
|
* @param {string} cartItemKey Cart item being updated.
|
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
export function* removeItemFromCart(
|
|
|
|
cartItemKey: string
|
|
|
|
): Generator< unknown, void, { response: CartResponse } > {
|
2020-04-07 11:03:22 +00:00
|
|
|
yield itemIsPendingDelete( cartItemKey );
|
2020-02-28 02:05:10 +00:00
|
|
|
|
|
|
|
try {
|
2020-03-19 11:50:51 +00:00
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: `/wc/store/v1/cart/remove-item`,
|
2021-04-20 15:44:49 +00:00
|
|
|
data: {
|
|
|
|
key: cartItemKey,
|
|
|
|
},
|
2020-03-05 19:11:39 +00:00
|
|
|
method: 'POST',
|
2020-02-28 02:05:10 +00:00
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
|
2020-03-19 11:50:51 +00:00
|
|
|
yield receiveCart( response );
|
2020-02-28 02:05:10 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
2020-04-09 12:52:31 +00:00
|
|
|
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
2020-02-28 02:05:10 +00:00
|
|
|
}
|
2020-04-07 11:03:22 +00:00
|
|
|
yield itemIsPendingDelete( cartItemKey, false );
|
2020-02-28 02:05:10 +00:00
|
|
|
}
|
2020-03-03 01:08:19 +00:00
|
|
|
|
|
|
|
/**
|
2020-03-09 02:09:47 +00:00
|
|
|
* Persists a quantity change the for specified cart item:
|
2020-03-03 01:08:19 +00:00
|
|
|
* - Calls API to set quantity.
|
|
|
|
* - If successful, yields action to update store.
|
|
|
|
* - If error, yields action to store error.
|
|
|
|
*
|
|
|
|
* @param {string} cartItemKey Cart item being updated.
|
2021-02-24 01:36:24 +00:00
|
|
|
* @param {number} quantity Specified (new) quantity.
|
2020-03-03 01:08:19 +00:00
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
export function* changeCartItemQuantity(
|
|
|
|
cartItemKey: string,
|
|
|
|
quantity: number
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- unclear how to represent multiple different yields as type
|
|
|
|
): Generator< unknown, void, any > {
|
2022-03-10 13:22:05 +00:00
|
|
|
const cartItem = yield controls.resolveSelect(
|
|
|
|
CART_STORE_KEY,
|
|
|
|
'getCartItem',
|
|
|
|
cartItemKey
|
|
|
|
);
|
2020-03-09 02:09:47 +00:00
|
|
|
if ( cartItem?.quantity === quantity ) {
|
|
|
|
return;
|
|
|
|
}
|
2021-12-10 15:26:57 +00:00
|
|
|
yield itemIsPendingQuantity( cartItemKey );
|
2020-03-03 01:08:19 +00:00
|
|
|
try {
|
2020-03-19 11:50:51 +00:00
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: '/wc/store/v1/cart/update-item',
|
2020-03-05 19:11:39 +00:00
|
|
|
method: 'POST',
|
|
|
|
data: {
|
|
|
|
key: cartItemKey,
|
|
|
|
quantity,
|
|
|
|
},
|
2020-03-03 01:08:19 +00:00
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
|
2020-03-19 11:50:51 +00:00
|
|
|
yield receiveCart( response );
|
2020-03-03 01:08:19 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
2020-04-09 12:52:31 +00:00
|
|
|
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
2020-03-03 01:08:19 +00:00
|
|
|
}
|
2020-04-07 11:03:22 +00:00
|
|
|
yield itemIsPendingQuantity( cartItemKey, false );
|
2020-03-03 01:08:19 +00:00
|
|
|
}
|
2020-03-05 19:54:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Selects a shipping rate.
|
|
|
|
*
|
2021-02-24 01:36:24 +00:00
|
|
|
* @param {string} rateId The id of the rate being selected.
|
|
|
|
* @param {number | string} [packageId] The key of the packages that we will
|
2022-04-08 13:47:19 +00:00
|
|
|
* select within.
|
2020-03-05 19:54:05 +00:00
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
export function* selectShippingRate(
|
|
|
|
rateId: string,
|
|
|
|
packageId = 0
|
|
|
|
): Generator< unknown, boolean, { response: CartResponse } > {
|
2020-03-05 19:54:05 +00:00
|
|
|
try {
|
2020-03-31 15:40:27 +00:00
|
|
|
yield shippingRatesBeingSelected( true );
|
2020-03-19 11:50:51 +00:00
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: `/wc/store/v1/cart/select-shipping-rate`,
|
2020-03-05 19:54:05 +00:00
|
|
|
method: 'POST',
|
|
|
|
data: {
|
2021-01-28 14:24:01 +00:00
|
|
|
package_id: packageId,
|
2020-03-05 19:54:05 +00:00
|
|
|
rate_id: rateId,
|
|
|
|
},
|
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
|
2020-03-19 11:50:51 +00:00
|
|
|
yield receiveCart( response );
|
2020-03-05 19:54:05 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
2020-03-31 15:40:27 +00:00
|
|
|
yield shippingRatesBeingSelected( false );
|
2020-04-09 12:52:31 +00:00
|
|
|
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
|
|
|
|
2020-03-13 20:05:45 +00:00
|
|
|
// Re-throw the error.
|
|
|
|
throw error;
|
2020-03-05 19:54:05 +00:00
|
|
|
}
|
2020-03-31 15:40:27 +00:00
|
|
|
yield shippingRatesBeingSelected( false );
|
2020-03-13 20:05:45 +00:00
|
|
|
return true;
|
2020-03-05 19:54:05 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 17:45:01 +00:00
|
|
|
/**
|
2022-06-10 16:59:25 +00:00
|
|
|
* Sets billing address locally, as opposed to updateCustomerData which sends it to the server.
|
2022-02-22 17:45:01 +00:00
|
|
|
*/
|
2022-06-10 16:59:25 +00:00
|
|
|
export const setBillingAddress = (
|
|
|
|
billingAddress: Partial< BillingAddress >
|
|
|
|
) => ( { type: types.SET_BILLING_ADDRESS, billingAddress } as const );
|
2022-02-22 17:45:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets shipping address locally, as opposed to updateCustomerData which sends it to the server.
|
|
|
|
*/
|
|
|
|
export const setShippingAddress = (
|
|
|
|
shippingAddress: Partial< ShippingAddress >
|
|
|
|
) => ( { type: types.SET_SHIPPING_ADDRESS, shippingAddress } as const );
|
|
|
|
|
2020-03-05 19:54:05 +00:00
|
|
|
/**
|
2021-02-24 01:36:24 +00:00
|
|
|
* Updates the shipping and/or billing address for the customer and returns an
|
|
|
|
* updated cart.
|
2020-03-05 19:54:05 +00:00
|
|
|
*
|
2021-02-24 01:36:24 +00:00
|
|
|
* @param {BillingAddressShippingAddress} customerData Address data to be updated; can contain both
|
2022-04-08 13:47:19 +00:00
|
|
|
* billing_address and shipping_address.
|
2020-03-05 19:54:05 +00:00
|
|
|
*/
|
2021-02-24 01:36:24 +00:00
|
|
|
export function* updateCustomerData(
|
2021-11-16 12:39:43 +00:00
|
|
|
customerData: Partial< BillingAddressShippingAddress >
|
2021-02-24 01:36:24 +00:00
|
|
|
): Generator< unknown, boolean, { response: CartResponse } > {
|
2020-11-20 15:13:35 +00:00
|
|
|
yield updatingCustomerData( true );
|
|
|
|
|
2020-03-05 19:54:05 +00:00
|
|
|
try {
|
2020-03-19 11:50:51 +00:00
|
|
|
const { response } = yield apiFetchWithHeaders( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: '/wc/store/v1/cart/update-customer',
|
2020-03-05 19:54:05 +00:00
|
|
|
method: 'POST',
|
2020-11-20 15:13:35 +00:00
|
|
|
data: customerData,
|
2020-03-05 19:54:05 +00:00
|
|
|
cache: 'no-store',
|
|
|
|
} );
|
|
|
|
|
2022-02-22 17:45:01 +00:00
|
|
|
yield receiveCartContents( response );
|
2020-03-05 19:54:05 +00:00
|
|
|
} catch ( error ) {
|
|
|
|
yield receiveError( error );
|
2020-11-20 15:13:35 +00:00
|
|
|
yield updatingCustomerData( false );
|
2020-04-09 12:52:31 +00:00
|
|
|
|
|
|
|
// If updated cart state was returned, also update that.
|
|
|
|
if ( error.data?.cart ) {
|
|
|
|
yield receiveCart( error.data.cart );
|
|
|
|
}
|
|
|
|
|
2020-03-13 20:05:45 +00:00
|
|
|
// rethrow error.
|
|
|
|
throw error;
|
2020-03-05 19:54:05 +00:00
|
|
|
}
|
2020-11-20 15:13:35 +00:00
|
|
|
|
|
|
|
yield updatingCustomerData( false );
|
2020-03-13 20:05:45 +00:00
|
|
|
return true;
|
2020-03-05 19:54:05 +00:00
|
|
|
}
|
2021-02-24 01:36:24 +00:00
|
|
|
|
2021-03-10 15:03:26 +00:00
|
|
|
export type CartAction = ReturnOrGeneratorYieldUnion<
|
2021-02-24 01:36:24 +00:00
|
|
|
| typeof receiveCart
|
2022-02-22 17:45:01 +00:00
|
|
|
| typeof receiveCartContents
|
2022-06-10 16:59:25 +00:00
|
|
|
| typeof setBillingAddress
|
2022-02-22 17:45:01 +00:00
|
|
|
| typeof setShippingAddress
|
2021-02-24 01:36:24 +00:00
|
|
|
| typeof receiveError
|
|
|
|
| typeof receiveApplyingCoupon
|
|
|
|
| typeof receiveRemovingCoupon
|
|
|
|
| typeof receiveCartItem
|
|
|
|
| typeof itemIsPendingQuantity
|
|
|
|
| typeof itemIsPendingDelete
|
|
|
|
| typeof updatingCustomerData
|
|
|
|
| typeof shippingRatesBeingSelected
|
2021-04-06 11:15:14 +00:00
|
|
|
| typeof setIsCartDataStale
|
2021-03-10 15:03:26 +00:00
|
|
|
| typeof updateCustomerData
|
|
|
|
| typeof removeItemFromCart
|
|
|
|
| typeof changeCartItemQuantity
|
|
|
|
| typeof addItemToCart
|
2021-02-24 01:36:24 +00:00
|
|
|
>;
|