147 lines
4.0 KiB
TypeScript
147 lines
4.0 KiB
TypeScript
/**
|
||
* External dependencies
|
||
*/
|
||
import classNames from 'classnames';
|
||
import { _n, sprintf } from '@wordpress/i18n';
|
||
import { decodeEntities } from '@wordpress/html-entities';
|
||
import { Panel } from '@woocommerce/blocks-checkout';
|
||
import Label from '@woocommerce/base-components/label';
|
||
import { useCallback } from '@wordpress/element';
|
||
import {
|
||
useShippingData,
|
||
useStoreEvents,
|
||
} from '@woocommerce/base-context/hooks';
|
||
import { sanitizeHTML } from '@woocommerce/utils';
|
||
import { debounce } from 'lodash';
|
||
import type { ReactElement } from 'react';
|
||
|
||
/**
|
||
* Internal dependencies
|
||
*/
|
||
import PackageRates from './package-rates';
|
||
import type { PackageProps } from './types';
|
||
import './style.scss';
|
||
|
||
export const ShippingRatesControlPackage = ( {
|
||
packageId,
|
||
className = '',
|
||
noResultsMessage,
|
||
renderOption,
|
||
packageData,
|
||
collapsible,
|
||
showItems,
|
||
}: PackageProps ): ReactElement => {
|
||
const { selectShippingRate } = useShippingData();
|
||
const { dispatchCheckoutEvent } = useStoreEvents();
|
||
const multiplePackages =
|
||
document.querySelectorAll(
|
||
'.wc-block-components-shipping-rates-control__package'
|
||
).length > 1;
|
||
|
||
// If showItems is not set, we check if we have multiple packages.
|
||
// We sometimes don't want to show items even if we have multiple packages.
|
||
const shouldShowItems = showItems ?? multiplePackages;
|
||
|
||
// If collapsible is not set, we check if we have multiple packages.
|
||
// We sometimes don't want to collapse even if we have multiple packages.
|
||
const shouldBeCollapsible = collapsible ?? multiplePackages;
|
||
|
||
const header = (
|
||
<>
|
||
{ ( shouldBeCollapsible || shouldShowItems ) && (
|
||
<div
|
||
className="wc-block-components-shipping-rates-control__package-title"
|
||
dangerouslySetInnerHTML={ {
|
||
__html: sanitizeHTML( packageData.name ),
|
||
} }
|
||
/>
|
||
) }
|
||
{ shouldShowItems && (
|
||
<ul className="wc-block-components-shipping-rates-control__package-items">
|
||
{ Object.values( packageData.items ).map( ( v ) => {
|
||
const name = decodeEntities( v.name );
|
||
const quantity = v.quantity;
|
||
return (
|
||
<li
|
||
key={ v.key }
|
||
className="wc-block-components-shipping-rates-control__package-item"
|
||
>
|
||
<Label
|
||
label={
|
||
quantity > 1
|
||
? `${ name } × ${ quantity }`
|
||
: `${ name }`
|
||
}
|
||
screenReaderLabel={ sprintf(
|
||
/* translators: %1$s name of the product (ie: Sunglasses), %2$d number of units in the current cart package */
|
||
_n(
|
||
'%1$s (%2$d unit)',
|
||
'%1$s (%2$d units)',
|
||
quantity,
|
||
'woo-gutenberg-products-block'
|
||
),
|
||
name,
|
||
quantity
|
||
) }
|
||
/>
|
||
</li>
|
||
);
|
||
} ) }
|
||
</ul>
|
||
) }
|
||
</>
|
||
);
|
||
const onSelectRate = debounce(
|
||
useCallback(
|
||
( newShippingRateId: string ) => {
|
||
selectShippingRate( newShippingRateId, packageId );
|
||
dispatchCheckoutEvent( 'set-selected-shipping-rate', {
|
||
shippingRateId: newShippingRateId,
|
||
} );
|
||
},
|
||
[ dispatchCheckoutEvent, packageId, selectShippingRate ]
|
||
),
|
||
1000
|
||
);
|
||
const packageRatesProps = {
|
||
className,
|
||
noResultsMessage,
|
||
rates: packageData.shipping_rates,
|
||
onSelectRate,
|
||
selectedRate: packageData.shipping_rates.find(
|
||
( rate ) => rate.selected
|
||
),
|
||
renderOption,
|
||
};
|
||
|
||
if ( shouldBeCollapsible ) {
|
||
return (
|
||
<Panel
|
||
className="wc-block-components-shipping-rates-control__package"
|
||
// initialOpen remembers only the first value provided to it, so by the
|
||
// time we know we have several packages, initialOpen would be hardcoded to true.
|
||
// If we're rendering a panel, we're more likely rendering several
|
||
// packages and we want to them to be closed initially.
|
||
initialOpen={ false }
|
||
title={ header }
|
||
>
|
||
<PackageRates { ...packageRatesProps } />
|
||
</Panel>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div
|
||
className={ classNames(
|
||
'wc-block-components-shipping-rates-control__package',
|
||
className
|
||
) }
|
||
>
|
||
{ header }
|
||
<PackageRates { ...packageRatesProps } />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default ShippingRatesControlPackage;
|