2022-10-04 12:02:28 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import { useShippingData } from '@woocommerce/base-context/hooks';
|
2024-05-31 03:49:36 +00:00
|
|
|
import clsx from 'clsx';
|
2022-10-04 12:02:28 +00:00
|
|
|
import { Icon, store, shipping } from '@wordpress/icons';
|
2023-03-17 15:32:03 +00:00
|
|
|
import { useEffect } from '@wordpress/element';
|
2023-05-25 05:31:15 +00:00
|
|
|
import { CART_STORE_KEY, VALIDATION_STORE_KEY } from '@woocommerce/block-data';
|
|
|
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
|
|
import { isPackageRateCollectable } from '@woocommerce/base-utils';
|
2023-10-11 14:09:43 +00:00
|
|
|
import { getSetting } from '@woocommerce/settings';
|
2022-10-04 12:02:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2022-10-11 15:46:59 +00:00
|
|
|
import { RatePrice, getLocalPickupPrices, getShippingPrices } from './shared';
|
|
|
|
import type { minMaxPrices } from './shared';
|
2022-12-22 13:36:25 +00:00
|
|
|
import { defaultLocalPickupText, defaultShippingText } from './constants';
|
2023-03-13 11:49:28 +00:00
|
|
|
import { shippingAddressHasValidationErrors } from '../../../../data/cart/utils';
|
2024-05-03 03:28:39 +00:00
|
|
|
import Button from '../../../../base/components/button';
|
2022-10-04 12:02:28 +00:00
|
|
|
|
2023-03-17 15:32:03 +00:00
|
|
|
const SHIPPING_RATE_ERROR = {
|
|
|
|
hidden: true,
|
2023-12-12 23:05:20 +00:00
|
|
|
message: __( 'Shipping options are not available', 'woocommerce' ),
|
2023-03-17 15:32:03 +00:00
|
|
|
};
|
|
|
|
|
2022-10-04 12:02:28 +00:00
|
|
|
const LocalPickupSelector = ( {
|
|
|
|
checked,
|
|
|
|
rate,
|
|
|
|
showPrice,
|
|
|
|
showIcon,
|
2022-10-05 10:54:48 +00:00
|
|
|
toggleText,
|
2022-11-18 13:20:04 +00:00
|
|
|
multiple,
|
2024-05-03 03:28:39 +00:00
|
|
|
onClick,
|
2022-10-04 12:02:28 +00:00
|
|
|
}: {
|
|
|
|
checked: string;
|
2022-10-11 15:46:59 +00:00
|
|
|
rate: minMaxPrices;
|
2022-10-04 12:02:28 +00:00
|
|
|
showPrice: boolean;
|
|
|
|
showIcon: boolean;
|
2022-10-05 10:54:48 +00:00
|
|
|
toggleText: string;
|
2022-11-18 13:20:04 +00:00
|
|
|
multiple: boolean;
|
2024-05-03 03:28:39 +00:00
|
|
|
onClick: () => void;
|
2022-10-04 12:02:28 +00:00
|
|
|
} ) => {
|
|
|
|
return (
|
2024-05-03 03:28:39 +00:00
|
|
|
<Button
|
|
|
|
role="radio"
|
|
|
|
removeTextWrap
|
|
|
|
onClick={ onClick }
|
2024-05-31 03:49:36 +00:00
|
|
|
className={ clsx( 'wc-block-checkout__shipping-method-option', {
|
|
|
|
'wc-block-checkout__shipping-method-option--selected':
|
|
|
|
checked === 'pickup',
|
|
|
|
} ) }
|
2022-10-04 12:02:28 +00:00
|
|
|
>
|
|
|
|
{ showIcon === true && (
|
|
|
|
<Icon
|
|
|
|
icon={ store }
|
|
|
|
size={ 28 }
|
2022-10-20 10:48:46 +00:00
|
|
|
className="wc-block-checkout__shipping-method-option-icon"
|
2022-10-04 12:02:28 +00:00
|
|
|
/>
|
|
|
|
) }
|
2022-10-20 10:48:46 +00:00
|
|
|
<span className="wc-block-checkout__shipping-method-option-title">
|
2022-10-05 10:54:48 +00:00
|
|
|
{ toggleText }
|
2022-10-04 12:02:28 +00:00
|
|
|
</span>
|
2022-10-11 15:46:59 +00:00
|
|
|
{ showPrice === true && (
|
2022-11-18 13:20:04 +00:00
|
|
|
<RatePrice
|
|
|
|
multiple={ multiple }
|
|
|
|
minRate={ rate.min }
|
|
|
|
maxRate={ rate.max }
|
|
|
|
/>
|
2022-10-11 15:46:59 +00:00
|
|
|
) }
|
2024-05-03 03:28:39 +00:00
|
|
|
</Button>
|
2022-10-04 12:02:28 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const ShippingSelector = ( {
|
|
|
|
checked,
|
|
|
|
rate,
|
|
|
|
showPrice,
|
|
|
|
showIcon,
|
2022-10-05 10:54:48 +00:00
|
|
|
toggleText,
|
2024-05-03 03:28:39 +00:00
|
|
|
onClick,
|
2023-03-13 11:49:28 +00:00
|
|
|
shippingCostRequiresAddress = false,
|
2022-10-04 12:02:28 +00:00
|
|
|
}: {
|
|
|
|
checked: string;
|
2022-10-11 15:46:59 +00:00
|
|
|
rate: minMaxPrices;
|
2022-10-04 12:02:28 +00:00
|
|
|
showPrice: boolean;
|
|
|
|
showIcon: boolean;
|
2023-03-13 11:49:28 +00:00
|
|
|
shippingCostRequiresAddress: boolean;
|
2024-05-03 03:28:39 +00:00
|
|
|
onClick: () => void;
|
2022-10-05 10:54:48 +00:00
|
|
|
toggleText: string;
|
2022-10-04 12:02:28 +00:00
|
|
|
} ) => {
|
2023-05-25 05:31:15 +00:00
|
|
|
const hasShippableRates = useSelect( ( select ) => {
|
|
|
|
const rates = select( CART_STORE_KEY ).getShippingRates();
|
|
|
|
return rates.some(
|
|
|
|
( { shipping_rates: shippingRate } ) =>
|
|
|
|
! shippingRate.every( isPackageRateCollectable )
|
|
|
|
);
|
|
|
|
} );
|
2023-03-13 11:49:28 +00:00
|
|
|
const rateShouldBeHidden =
|
2023-05-25 05:31:15 +00:00
|
|
|
shippingCostRequiresAddress &&
|
|
|
|
shippingAddressHasValidationErrors() &&
|
|
|
|
! hasShippableRates;
|
2023-03-17 15:32:03 +00:00
|
|
|
const hasShippingPrices = rate.min !== undefined && rate.max !== undefined;
|
|
|
|
const { setValidationErrors, clearValidationError } =
|
|
|
|
useDispatch( VALIDATION_STORE_KEY );
|
|
|
|
useEffect( () => {
|
|
|
|
if ( checked === 'shipping' && ! hasShippingPrices ) {
|
|
|
|
setValidationErrors( {
|
|
|
|
'shipping-rates-error': SHIPPING_RATE_ERROR,
|
|
|
|
} );
|
|
|
|
} else {
|
|
|
|
clearValidationError( 'shipping-rates-error' );
|
|
|
|
}
|
|
|
|
}, [
|
|
|
|
checked,
|
|
|
|
clearValidationError,
|
|
|
|
hasShippingPrices,
|
|
|
|
setValidationErrors,
|
|
|
|
] );
|
2022-10-04 12:02:28 +00:00
|
|
|
const Price =
|
2023-03-13 11:49:28 +00:00
|
|
|
rate.min === undefined || rateShouldBeHidden ? (
|
2022-10-20 10:48:46 +00:00
|
|
|
<span className="wc-block-checkout__shipping-method-option-price">
|
2023-12-12 23:05:20 +00:00
|
|
|
{ __( 'calculated with an address', 'woocommerce' ) }
|
2022-10-04 12:02:28 +00:00
|
|
|
</span>
|
|
|
|
) : (
|
2022-10-11 15:46:59 +00:00
|
|
|
<RatePrice minRate={ rate.min } maxRate={ rate.max } />
|
2022-10-04 12:02:28 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
return (
|
2024-05-03 03:28:39 +00:00
|
|
|
<Button
|
|
|
|
role="radio"
|
|
|
|
onClick={ onClick }
|
|
|
|
removeTextWrap
|
2024-05-31 03:49:36 +00:00
|
|
|
className={ clsx( 'wc-block-checkout__shipping-method-option', {
|
|
|
|
'wc-block-checkout__shipping-method-option--selected':
|
|
|
|
checked === 'shipping',
|
|
|
|
} ) }
|
2022-10-04 12:02:28 +00:00
|
|
|
>
|
|
|
|
{ showIcon === true && (
|
|
|
|
<Icon
|
|
|
|
icon={ shipping }
|
|
|
|
size={ 28 }
|
2022-10-20 10:48:46 +00:00
|
|
|
className="wc-block-checkout__shipping-method-option-icon"
|
2022-10-04 12:02:28 +00:00
|
|
|
/>
|
|
|
|
) }
|
2022-10-20 10:48:46 +00:00
|
|
|
<span className="wc-block-checkout__shipping-method-option-title">
|
2022-10-05 10:54:48 +00:00
|
|
|
{ toggleText }
|
2022-10-04 12:02:28 +00:00
|
|
|
</span>
|
|
|
|
{ showPrice === true && Price }
|
2024-05-03 03:28:39 +00:00
|
|
|
</Button>
|
2022-10-04 12:02:28 +00:00
|
|
|
);
|
|
|
|
};
|
2024-05-03 03:28:39 +00:00
|
|
|
|
2022-10-04 12:02:28 +00:00
|
|
|
const Block = ( {
|
|
|
|
checked,
|
|
|
|
onChange,
|
|
|
|
showPrice,
|
|
|
|
showIcon,
|
2022-10-05 10:54:48 +00:00
|
|
|
localPickupText,
|
|
|
|
shippingText,
|
2022-10-04 12:02:28 +00:00
|
|
|
}: {
|
|
|
|
checked: string;
|
|
|
|
onChange: ( value: string ) => void;
|
|
|
|
showPrice: boolean;
|
|
|
|
showIcon: boolean;
|
2022-10-05 10:54:48 +00:00
|
|
|
localPickupText: string;
|
|
|
|
shippingText: string;
|
2022-10-04 12:02:28 +00:00
|
|
|
} ): JSX.Element | null => {
|
2022-10-18 16:31:06 +00:00
|
|
|
const { shippingRates } = useShippingData();
|
2023-10-11 14:09:43 +00:00
|
|
|
const shippingCostRequiresAddress = getSetting< boolean >(
|
|
|
|
'shippingCostRequiresAddress',
|
|
|
|
false
|
|
|
|
);
|
2024-04-02 11:34:32 +00:00
|
|
|
const localPickupTextFromSettings = getSetting< string >(
|
|
|
|
'localPickupText',
|
|
|
|
localPickupText || defaultLocalPickupText
|
|
|
|
);
|
2022-10-04 12:02:28 +00:00
|
|
|
|
|
|
|
return (
|
2024-05-03 03:28:39 +00:00
|
|
|
<div
|
2022-10-20 10:48:46 +00:00
|
|
|
id="shipping-method"
|
2024-05-03 03:28:39 +00:00
|
|
|
// components-button-group is here for backwards compatibility, in case themes or plugins rely on it.
|
|
|
|
className="components-button-group wc-block-checkout__shipping-method-container"
|
|
|
|
role="radiogroup"
|
2022-10-04 12:02:28 +00:00
|
|
|
>
|
|
|
|
<ShippingSelector
|
|
|
|
checked={ checked }
|
2024-05-03 03:28:39 +00:00
|
|
|
onClick={ () => {
|
|
|
|
onChange( 'shipping' );
|
|
|
|
} }
|
2022-10-11 15:46:59 +00:00
|
|
|
rate={ getShippingPrices( shippingRates[ 0 ]?.shipping_rates ) }
|
2022-10-04 12:02:28 +00:00
|
|
|
showPrice={ showPrice }
|
|
|
|
showIcon={ showIcon }
|
2023-03-13 11:49:28 +00:00
|
|
|
shippingCostRequiresAddress={ shippingCostRequiresAddress }
|
2022-12-22 13:36:25 +00:00
|
|
|
toggleText={ shippingText || defaultShippingText }
|
2022-10-04 12:02:28 +00:00
|
|
|
/>
|
|
|
|
<LocalPickupSelector
|
|
|
|
checked={ checked }
|
2024-05-03 03:28:39 +00:00
|
|
|
onClick={ () => {
|
|
|
|
onChange( 'pickup' );
|
|
|
|
} }
|
2022-10-11 15:46:59 +00:00
|
|
|
rate={ getLocalPickupPrices(
|
|
|
|
shippingRates[ 0 ]?.shipping_rates
|
|
|
|
) }
|
2022-11-18 13:20:04 +00:00
|
|
|
multiple={ shippingRates.length > 1 }
|
2022-10-04 12:02:28 +00:00
|
|
|
showPrice={ showPrice }
|
|
|
|
showIcon={ showIcon }
|
2024-04-02 11:34:32 +00:00
|
|
|
toggleText={ localPickupTextFromSettings }
|
2022-10-04 12:02:28 +00:00
|
|
|
/>
|
2024-05-03 03:28:39 +00:00
|
|
|
</div>
|
2022-10-04 12:02:28 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Block;
|