woocommerce/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/shipping-rates-control-package/package-rates.tsx

100 lines
2.6 KiB
TypeScript
Raw Normal View History

/**
* External dependencies
*/
import { useState, useEffect } from '@wordpress/element';
import {
RadioControl,
RadioControlOptionLayout,
} from '@woocommerce/blocks-components';
import type { CartShippingPackageShippingRate } from '@woocommerce/types';
import { usePrevious } from '@woocommerce/base-hooks';
/**
* Internal dependencies
*/
import { renderPackageRateOption } from './render-package-rate-option';
import type { PackageRateRenderOption } from '../shipping-rates-control-package';
interface PackageRates {
onSelectRate: ( selectedRateId: string ) => void;
rates: CartShippingPackageShippingRate[];
renderOption?: PackageRateRenderOption | undefined;
className?: string;
noResultsMessage: JSX.Element;
selectedRate: CartShippingPackageShippingRate | undefined;
disabled?: boolean;
}
const PackageRates = ( {
className = '',
noResultsMessage,
onSelectRate,
rates,
renderOption = renderPackageRateOption,
selectedRate,
disabled = false,
}: PackageRates ): JSX.Element => {
const selectedRateId = selectedRate?.rate_id || '';
const previousSelectedRateId = usePrevious( selectedRateId );
// Store selected rate ID in local state so shipping rates changes are shown in the UI instantly.
const [ selectedOption, setSelectedOption ] = useState( () => {
if ( selectedRateId ) {
return selectedRateId;
}
// Default to first rate if no rate is selected.
return rates[ 0 ]?.rate_id;
} );
// Update the selected option if cart state changes in the data store.
useEffect( () => {
Fix total shipping display info when no shipping method is available (https://github.com/woocommerce/woocommerce-blocks/pull/8819) * Fix total shipping info when no shipping are available * Fix a logical error for displaying shipping info * Fix failing unit tests * Run unit test for the Cart instead of the Checkout The calculator is only available for the Cart Block, so it doesn't make sense to run this test for the Checkout Block * Fix no shipping methods and incomplete address conflict When there are no shipping methods (except for local pickup), we would like to inform the shopper that there are no shipping options available even though the address is complete The solution we found is to check the address on the Cart Block only * Refactor code * Check whether rate is collectible without using hardcoded id * Correctly negate hasCollectibleRate result * Add notice when shipping is selected but no methods are available yet (https://github.com/woocommerce/woocommerce-blocks/pull/9171) * Create useShippingTotalWarning hook * Show notices above checkout sidebar * Call hook to show notice in Checkout block * Remove unused imports * Update hook name to useShowShippingTotalWarning * Move hook to its own file * Import shipping data internally (without alias) * Remove unused imports * Move import to correct place * Return early to avoid if else * Refactor useShowShippingTotalWarning * Get shipping rates directly from the cart instead of the hook * Show shipping cost when price information is available * Check if the passed rates are considered selected * Prevent errors when no rates are available --------- Co-authored-by: Thomas Roberts <thomas.roberts@automattic.com> Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> Co-authored-by: Tarun Vijwani <tarun.vijwani@automattic.com>
2023-05-25 05:31:15 +00:00
if (
selectedRateId &&
selectedRateId !== previousSelectedRateId &&
selectedRateId !== selectedOption
Fix total shipping display info when no shipping method is available (https://github.com/woocommerce/woocommerce-blocks/pull/8819) * Fix total shipping info when no shipping are available * Fix a logical error for displaying shipping info * Fix failing unit tests * Run unit test for the Cart instead of the Checkout The calculator is only available for the Cart Block, so it doesn't make sense to run this test for the Checkout Block * Fix no shipping methods and incomplete address conflict When there are no shipping methods (except for local pickup), we would like to inform the shopper that there are no shipping options available even though the address is complete The solution we found is to check the address on the Cart Block only * Refactor code * Check whether rate is collectible without using hardcoded id * Correctly negate hasCollectibleRate result * Add notice when shipping is selected but no methods are available yet (https://github.com/woocommerce/woocommerce-blocks/pull/9171) * Create useShippingTotalWarning hook * Show notices above checkout sidebar * Call hook to show notice in Checkout block * Remove unused imports * Update hook name to useShowShippingTotalWarning * Move hook to its own file * Import shipping data internally (without alias) * Remove unused imports * Move import to correct place * Return early to avoid if else * Refactor useShowShippingTotalWarning * Get shipping rates directly from the cart instead of the hook * Show shipping cost when price information is available * Check if the passed rates are considered selected * Prevent errors when no rates are available --------- Co-authored-by: Thomas Roberts <thomas.roberts@automattic.com> Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com> Co-authored-by: Tarun Vijwani <tarun.vijwani@automattic.com>
2023-05-25 05:31:15 +00:00
) {
setSelectedOption( selectedRateId );
}
}, [ selectedRateId, selectedOption, previousSelectedRateId ] );
// Update the data store when the local selected rate changes.
useEffect( () => {
if ( selectedOption ) {
onSelectRate( selectedOption );
}
}, [ onSelectRate, selectedOption ] );
if ( rates.length === 0 ) {
return noResultsMessage;
}
if ( rates.length > 1 ) {
return (
<RadioControl
className={ className }
onChange={ ( value: string ) => {
setSelectedOption( value );
onSelectRate( value );
} }
disabled={ disabled }
selected={ selectedOption }
options={ rates.map( renderOption ) }
/>
);
}
const { label, secondaryLabel, description, secondaryDescription } =
renderOption( rates[ 0 ] );
return (
<RadioControlOptionLayout
label={ label }
secondaryLabel={ secondaryLabel }
description={ description }
secondaryDescription={ secondaryDescription }
/>
);
};
export default PackageRates;