Pre-hydrate Mini Cart Block woocommerce/woocommerce-blocks#5882 (https://github.com/woocommerce/woocommerce-blocks/pull/5892)
* Pre-hydrate Mini Cart Block woocommerce/woocommerce-blocks#5882 Pre-hydrate Mini Cart Block * try to fix test * fix wrong behaviour
This commit is contained in:
parent
dceb480e00
commit
71bd69ad07
|
@ -11,11 +11,18 @@ import {
|
|||
getCurrencyFromPriceResponse,
|
||||
} from '@woocommerce/price-format';
|
||||
import { getSettingWithCoercion } from '@woocommerce/settings';
|
||||
import { isBoolean, isString } from '@woocommerce/types';
|
||||
import {
|
||||
CartResponseTotals,
|
||||
isBoolean,
|
||||
isString,
|
||||
isCartResponseTotals,
|
||||
isNumber,
|
||||
} from '@woocommerce/types';
|
||||
import {
|
||||
unmountComponentAtNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from '@wordpress/element';
|
||||
import { sprintf, _n } from '@wordpress/i18n';
|
||||
|
@ -42,7 +49,20 @@ const MiniCartBlock = ( {
|
|||
style,
|
||||
contents = '',
|
||||
}: Props ): JSX.Element => {
|
||||
const { cartItemsCount, cartIsLoading, cartTotals } = useStoreCart();
|
||||
const {
|
||||
cartItemsCount: cartItemsCountFromApi,
|
||||
cartIsLoading,
|
||||
cartTotals: cartTotalsFromApi,
|
||||
} = useStoreCart();
|
||||
|
||||
const isFirstLoadingCompleted = useRef( cartIsLoading );
|
||||
|
||||
useEffect( () => {
|
||||
if ( isFirstLoadingCompleted.current && ! cartIsLoading ) {
|
||||
isFirstLoadingCompleted.current = false;
|
||||
}
|
||||
}, [ cartIsLoading, isFirstLoadingCompleted ] );
|
||||
|
||||
const [ isOpen, setIsOpen ] = useState< boolean >( isInitiallyOpen );
|
||||
// We already rendered the HTML drawer placeholder, so we want to skip the
|
||||
// slide in animation.
|
||||
|
@ -120,8 +140,29 @@ const MiniCartBlock = ( {
|
|||
isBoolean
|
||||
);
|
||||
|
||||
const preFetchedCartTotals = getSettingWithCoercion< CartResponseTotals | null >(
|
||||
'cartTotals',
|
||||
null,
|
||||
isCartResponseTotals
|
||||
);
|
||||
|
||||
const preFetchedCartItemsCount = getSettingWithCoercion< number >(
|
||||
'cartItemsCount',
|
||||
0,
|
||||
isNumber
|
||||
);
|
||||
|
||||
const taxLabel = getSettingWithCoercion( 'taxLabel', '', isString );
|
||||
|
||||
const cartTotals =
|
||||
! isFirstLoadingCompleted.current || preFetchedCartTotals === null
|
||||
? cartTotalsFromApi
|
||||
: preFetchedCartTotals;
|
||||
|
||||
const cartItemsCount = ! isFirstLoadingCompleted.current
|
||||
? cartItemsCountFromApi
|
||||
: preFetchedCartItemsCount;
|
||||
|
||||
const subTotal = showIncludingTax
|
||||
? parseInt( cartTotals.total_items, 10 ) +
|
||||
parseInt( cartTotals.total_items_tax, 10 )
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export const isBoolean = ( term: unknown ): term is boolean => {
|
||||
return typeof term === 'boolean';
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { CartResponseTotals } from '../type-defs';
|
||||
import { isObject } from './object';
|
||||
|
||||
// It is the only way to create a type that contains all the object's keys and gets type-checking.
|
||||
// This is useful because we want to check that the keys object ALWAYS contains all the object's keys.
|
||||
// https://stackoverflow.com/questions/52028791/make-a-generic-type-arraykeyof-t-require-all-keys-of-t
|
||||
|
||||
type CartResponseTotalsKeys = Record< keyof CartResponseTotals, 0 >;
|
||||
|
||||
export const isCartResponseTotals = (
|
||||
value: unknown
|
||||
): value is CartResponseTotals => {
|
||||
if ( ! isObject( value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const keys: CartResponseTotalsKeys = {
|
||||
total_items: 0,
|
||||
total_items_tax: 0,
|
||||
total_fees: 0,
|
||||
total_fees_tax: 0,
|
||||
total_discount: 0,
|
||||
total_discount_tax: 0,
|
||||
total_shipping: 0,
|
||||
total_shipping_tax: 0,
|
||||
total_price: 0,
|
||||
total_tax: 0,
|
||||
tax_lines: 0,
|
||||
currency_code: 0,
|
||||
currency_symbol: 0,
|
||||
currency_minor_unit: 0,
|
||||
currency_decimal_separator: 0,
|
||||
currency_thousand_separator: 0,
|
||||
currency_prefix: 0,
|
||||
currency_suffix: 0,
|
||||
};
|
||||
|
||||
return Object.keys( keys ).every( ( key ) => key in value );
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
export const isError = ( term: unknown ): term is Error => {
|
||||
return term instanceof Error;
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export const isFunction = < T extends Function, U >(
|
||||
term: T | U
|
||||
): term is T => {
|
||||
return typeof term === 'function';
|
||||
};
|
|
@ -1,44 +1,8 @@
|
|||
export const isNull = < T >( term: T | null ): term is null => {
|
||||
return term === null;
|
||||
};
|
||||
|
||||
export const isNumber = < U >( term: number | U ): term is number => {
|
||||
return typeof term === 'number';
|
||||
};
|
||||
|
||||
export const isString = < U >( term: string | U ): term is string => {
|
||||
return typeof term === 'string';
|
||||
};
|
||||
|
||||
export const isObject = < T extends Record< string, unknown >, U >(
|
||||
term: T | U
|
||||
): term is NonNullable< T > => {
|
||||
return (
|
||||
! isNull( term ) &&
|
||||
term instanceof Object &&
|
||||
term.constructor === Object
|
||||
);
|
||||
};
|
||||
|
||||
export function objectHasProp< P extends PropertyKey >(
|
||||
target: unknown,
|
||||
property: P
|
||||
): target is { [ K in P ]: unknown } {
|
||||
// The `in` operator throws a `TypeError` for non-object values.
|
||||
return isObject( target ) && property in target;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export const isFunction = < T extends Function, U >(
|
||||
term: T | U
|
||||
): term is T => {
|
||||
return typeof term === 'function';
|
||||
};
|
||||
|
||||
export const isBoolean = ( term: unknown ): term is boolean => {
|
||||
return typeof term === 'boolean';
|
||||
};
|
||||
|
||||
export const isError = ( term: unknown ): term is Error => {
|
||||
return term instanceof Error;
|
||||
};
|
||||
export * from './boolean';
|
||||
export * from './cart-response-totals';
|
||||
export * from './error';
|
||||
export * from './function';
|
||||
export * from './null';
|
||||
export * from './number';
|
||||
export * from './object';
|
||||
export * from './string';
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export const isNull = < T >( term: T | null ): term is null => {
|
||||
return term === null;
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
export const isNumber = < U >( term: number | U ): term is number => {
|
||||
return typeof term === 'number';
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
|
||||
import { isNull } from './null';
|
||||
|
||||
export const isObject = < T extends Record< string, unknown >, U >(
|
||||
term: T | U
|
||||
): term is NonNullable< T > => {
|
||||
return (
|
||||
! isNull( term ) &&
|
||||
term instanceof Object &&
|
||||
term.constructor === Object
|
||||
);
|
||||
};
|
||||
|
||||
export function objectHasProp< P extends PropertyKey >(
|
||||
target: unknown,
|
||||
property: P
|
||||
): target is { [ K in P ]: unknown } {
|
||||
// The `in` operator throws a `TypeError` for non-object values.
|
||||
return isObject( target ) && property in target;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export const isString = < U >( term: string | U ): term is string => {
|
||||
return typeof term === 'string';
|
||||
};
|
|
@ -118,10 +118,18 @@ class MiniCart extends AbstractBlock {
|
|||
''
|
||||
);
|
||||
|
||||
$cart_payload = $this->get_cart_payload();
|
||||
|
||||
$this->asset_data_registry->add(
|
||||
'displayCartPricesIncludingTax',
|
||||
$this->display_cart_prices_including_tax,
|
||||
false
|
||||
'cartTotals',
|
||||
isset( $cart_payload['totals'] ) ? $cart_payload['totals'] : null,
|
||||
null
|
||||
);
|
||||
|
||||
$this->asset_data_registry->add(
|
||||
'cartItemsCount',
|
||||
isset( $cart_payload['items_count'] ) ? $cart_payload['items_count'] : null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -447,6 +455,17 @@ class MiniCart extends AbstractBlock {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Cart Payload.
|
||||
*
|
||||
* @return object;
|
||||
*/
|
||||
protected function get_cart_payload() {
|
||||
return WC()->api->get_endpoint_data( '/wc/store/cart' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the supports array for this block type.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue