);
};
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-address.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-address.tsx
index 8bfa8cfcdcf..da7b8c6b827 100644
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-address.tsx
+++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-address.tsx
@@ -1,43 +1,46 @@
/**
* External dependencies
*/
-import { __ } from '@wordpress/i18n';
+import { __, sprintf } from '@wordpress/i18n';
import { formatShippingAddress } from '@woocommerce/base-utils';
-import { ShippingAddress as ShippingAddressType } from '@woocommerce/settings';
-import {
- ShippingLocation,
- PickupLocation,
- ShippingCalculatorButton,
-} from '@woocommerce/base-components/cart-checkout';
-import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
+import { useStoreCart } from '@woocommerce/base-context';
+import { ShippingCalculatorButton } from '@woocommerce/base-components/cart-checkout';
import { useSelect } from '@wordpress/data';
+import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
-export interface ShippingAddressProps {
- shippingAddress: ShippingAddressType;
-}
+/**
+ * Internal dependencies
+ */
+import { getPickupLocation } from './utils';
-export const ShippingAddress = ( {
- shippingAddress,
-}: ShippingAddressProps ): JSX.Element | null => {
+export const ShippingAddress = (): JSX.Element => {
+ const { shippingRates, shippingAddress } = useStoreCart();
const prefersCollection = useSelect( ( select ) =>
select( CHECKOUT_STORE_KEY ).prefersCollection()
);
- const hasFormattedAddress = !! formatShippingAddress( shippingAddress );
+ const formattedAddress = prefersCollection
+ ? getPickupLocation( shippingRates )
+ : formatShippingAddress( shippingAddress );
+
+ const addressLabel = prefersCollection
+ ? /* translators: %s location. */
+ __( 'Collection from %s', 'woocommerce' )
+ : /* translators: %s location. */
+ __( 'Delivers to %s', 'woocommerce' );
+
+ const calculatorLabel =
+ ! formattedAddress || prefersCollection
+ ? __( 'Enter address to check delivery options', 'woocommerce' )
+ : __( 'Change address', 'woocommerce' );
- const label = hasFormattedAddress
- ? __( 'Change address', 'woocommerce' )
- : __( 'Enter address to check delivery options', 'woocommerce' );
- const formattedLocation = formatShippingAddress( shippingAddress );
return (
- <>
- { prefersCollection ? (
-
+ { formattedAddress
+ ? sprintf( addressLabel, formattedAddress ) + ' '
+ : null }
+
+
);
};
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-placeholder.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-placeholder.tsx
deleted file mode 100644
index ba676f704d4..00000000000
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-placeholder.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * External dependencies
- */
-import { __ } from '@wordpress/i18n';
-import { ShippingCalculatorButton } from '@woocommerce/base-components/cart-checkout';
-
-export interface ShippingPlaceholderProps {
- showCalculator: boolean;
- isCheckout?: boolean;
- addressProvided: boolean;
-}
-
-export const ShippingPlaceholder = ( {
- showCalculator,
- addressProvided,
- isCheckout = false,
-}: ShippingPlaceholderProps ): JSX.Element => {
- if ( ! showCalculator ) {
- const label = addressProvided
- ? __( 'No available delivery option', 'woocommerce' )
- : __( 'Enter address to calculate', 'woocommerce' );
- return (
-
- );
-};
-
-export default ShippingPlaceholder;
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-via.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-via.tsx
index a18e90d54e4..a9c788d4b03 100644
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-via.tsx
+++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-via.tsx
@@ -2,22 +2,23 @@
* External dependencies
*/
import { decodeEntities } from '@wordpress/html-entities';
+import { useStoreCart } from '@woocommerce/base-context';
+import { getSelectedShippingRateNames } from '@woocommerce/base-utils';
-export const ShippingVia = ( {
- selectedShippingRates,
-}: {
- selectedShippingRates: string[];
-} ): JSX.Element => {
- return (
-
+export const ShippingVia = (): JSX.Element | null => {
+ const { shippingRates } = useStoreCart();
+ const rateNames = getSelectedShippingRateNames( shippingRates );
+ return rateNames ? (
+
{ decodeEntities(
- selectedShippingRates
+ rateNames
.filter(
- ( item, index ) =>
- selectedShippingRates.indexOf( item ) === index
+ ( item, index ) => rateNames.indexOf( item ) === index
)
.join( ', ' )
) }
- );
+ ) : null;
};
+
+export default ShippingVia;
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/style.scss
index 001dd223627..570bc21c582 100644
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/style.scss
+++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/style.scss
@@ -11,6 +11,7 @@
text-transform: uppercase;
}
+ .wc-block-components-totals-shipping__delivery-options-notice,
.wc-block-components-shipping-address {
margin-top: $gap;
display: block;
@@ -54,6 +55,11 @@
.wc-block-components-shipping-placeholder__value {
@include font-size(small);
}
+
+ .wc-block-components-totals-shipping__via {
+ @include font-size(small);
+ width: 100%;
+ }
}
// Extra classes for specificity.
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/index.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/index.tsx
index 209d44a6e50..5bce5da4e69 100644
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/index.tsx
+++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/index.tsx
@@ -3,8 +3,10 @@
*/
import { screen, render } from '@testing-library/react';
import { SlotFillProvider } from '@woocommerce/blocks-checkout';
-import { previewCart as mockPreviewCart } from '@woocommerce/resource-previews';
+import { ShippingCalculatorContext } from '@woocommerce/base-components/cart-checkout/shipping-calculator/context';
import * as wpData from '@wordpress/data';
+import { CartShippingRate } from '@woocommerce/types';
+import { previewCart as mockPreviewCart } from '@woocommerce/resource-previews';
import * as baseContextHooks from '@woocommerce/base-context/hooks';
/**
@@ -51,6 +53,54 @@ const shippingAddress = {
phone: '+1234567890',
};
+const shippingRates = [
+ {
+ package_id: 0,
+ name: 'Initial Shipment',
+ destination: {
+ address_1: '30 Test Street',
+ address_2: 'Apt 1 Shipping',
+ city: 'Liverpool',
+ state: '',
+ postcode: 'L1 0BP',
+ country: 'GB',
+ },
+ items: [
+ {
+ key: 'acf4b89d3d503d8252c9c4ba75ddbf6d',
+ name: 'Test product',
+ quantity: 1,
+ },
+ ],
+ shipping_rates: [
+ {
+ rate_id: 'flat_rate:1',
+ name: 'Shipping',
+ description: '',
+ delivery_time: '',
+ price: '0',
+ taxes: '0',
+ instance_id: 13,
+ method_id: 'flat_rate',
+ meta_data: [
+ {
+ key: 'Items',
+ value: 'Test product × 1',
+ },
+ ],
+ selected: false,
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_thousand_separator: ',',
+ currency_prefix: '$',
+ currency_suffix: '',
+ },
+ ],
+ },
+] as CartShippingRate[];
+
jest.mock( '@woocommerce/base-context/hooks', () => {
return {
__esModule: true,
@@ -59,117 +109,20 @@ jest.mock( '@woocommerce/base-context/hooks', () => {
useStoreCart: jest.fn(),
};
} );
+
baseContextHooks.useShippingData.mockReturnValue( {
needsShipping: true,
selectShippingRate: jest.fn(),
- shippingRates: [
- {
- package_id: 0,
- name: 'Shipping method',
- destination: {
- address_1: '',
- address_2: '',
- city: '',
- state: '',
- postcode: '',
- country: '',
- },
- items: [
- {
- key: 'fb0c0a746719a7596f296344b80cb2b6',
- name: 'Hoodie - Blue, Yes',
- quantity: 1,
- },
- {
- key: '1f0e3dad99908345f7439f8ffabdffc4',
- name: 'Beanie',
- quantity: 1,
- },
- ],
- shipping_rates: [
- {
- rate_id: 'flat_rate:1',
- name: 'Flat rate',
- description: '',
- delivery_time: '',
- price: '500',
- taxes: '0',
- instance_id: 1,
- method_id: 'flat_rate',
- meta_data: [
- {
- key: 'Items',
- value: 'Hoodie - Blue, Yes × 1, Beanie × 1',
- },
- ],
- selected: false,
- currency_code: 'USD',
- currency_symbol: '$',
- currency_minor_unit: 2,
- currency_decimal_separator: '.',
- currency_thousand_separator: ',',
- currency_prefix: '$',
- currency_suffix: '',
- },
- {
- rate_id: 'local_pickup:2',
- name: 'Local pickup',
- description: '',
- delivery_time: '',
- price: '0',
- taxes: '0',
- instance_id: 2,
- method_id: 'local_pickup',
- meta_data: [
- {
- key: 'Items',
- value: 'Hoodie - Blue, Yes × 1, Beanie × 1',
- },
- ],
- selected: false,
- currency_code: 'USD',
- currency_symbol: '$',
- currency_minor_unit: 2,
- currency_decimal_separator: '.',
- currency_thousand_separator: ',',
- currency_prefix: '$',
- currency_suffix: '',
- },
- {
- rate_id: 'free_shipping:5',
- name: 'Free shipping',
- description: '',
- delivery_time: '',
- price: '0',
- taxes: '0',
- instance_id: 5,
- method_id: 'free_shipping',
- meta_data: [
- {
- key: 'Items',
- value: 'Hoodie - Blue, Yes × 1, Beanie × 1',
- },
- ],
- selected: true,
- currency_code: 'USD',
- currency_symbol: '$',
- currency_minor_unit: 2,
- currency_decimal_separator: '.',
- currency_thousand_separator: ',',
- currency_prefix: '$',
- currency_suffix: '',
- },
- ],
- },
- ],
+ shippingRates,
} );
+
baseContextHooks.useStoreCart.mockReturnValue( {
cartItems: mockPreviewCart.items,
- cartTotals: [ mockPreviewCart.totals ],
+ cartTotals: mockPreviewCart.totals,
cartCoupons: mockPreviewCart.coupons,
cartFees: mockPreviewCart.fees,
cartNeedsShipping: mockPreviewCart.needs_shipping,
- shippingRates: [],
+ shippingRates,
shippingAddress,
billingAddress: mockPreviewCart.billing_address,
cartHasCalculatedShipping: mockPreviewCart.has_calculated_shipping,
@@ -179,141 +132,73 @@ baseContextHooks.useStoreCart.mockReturnValue( {
describe( 'TotalsShipping', () => {
it( 'shows FREE if shipping cost is 0', () => {
baseContextHooks.useStoreCart.mockReturnValue( {
- cartItems: mockPreviewCart.items,
- cartTotals: [ mockPreviewCart.totals ],
- cartCoupons: mockPreviewCart.coupons,
- cartFees: mockPreviewCart.fees,
- cartNeedsShipping: mockPreviewCart.needs_shipping,
+ ...baseContextHooks.useStoreCart(),
shippingRates: [
- {
- package_id: 0,
- name: 'Initial Shipment',
- destination: {
- address_1: '30 Test Street',
- address_2: 'Apt 1 Shipping',
- city: 'Liverpool',
- state: '',
- postcode: 'L1 0BP',
- country: 'GB',
- },
- items: [
- {
- key: 'acf4b89d3d503d8252c9c4ba75ddbf6d',
- name: 'Test product',
- quantity: 1,
- },
- ],
- shipping_rates: [
- {
- rate_id: 'free_shipping:1',
- name: 'Free shipping',
- description: '',
- delivery_time: '',
- price: '0',
- taxes: '0',
- instance_id: 13,
- method_id: 'free_shipping',
- meta_data: [
- {
- key: 'Items',
- value: 'Test product × 1',
- },
- ],
- selected: false,
- currency_code: 'USD',
- currency_symbol: '$',
- currency_minor_unit: 2,
- currency_decimal_separator: '.',
- currency_thousand_separator: ',',
- currency_prefix: '$',
- currency_suffix: '',
- },
- ],
- },
+ ...shippingRates,
+ { ...shippingRates[ 0 ], price: '0' },
],
- shippingAddress,
- billingAddress: mockPreviewCart.billing_address,
- cartHasCalculatedShipping: mockPreviewCart.has_calculated_shipping,
- isLoadingRates: false,
+ cartTotals: {
+ ...mockPreviewCart.totals,
+ total_shipping: '0',
+ total_shipping_tax: '0',
+ },
} );
const { rerender } = render(
-
+
);
+
expect(
screen.getByText( 'Free', { exact: true } )
).toBeInTheDocument();
expect( screen.queryByText( '0.00' ) ).not.toBeInTheDocument();
+ baseContextHooks.useStoreCart.mockReturnValue( {
+ ...baseContextHooks.useStoreCart(),
+ shippingRates: [
+ ...shippingRates,
+ { ...shippingRates[ 0 ], price: '5678' },
+ ],
+ cartTotals: {
+ ...mockPreviewCart.totals,
+ total_shipping: '5678',
+ total_shipping_tax: '0',
+ currency_code: 'USD',
+ currency_symbol: '$',
+ currency_minor_unit: 2,
+ currency_decimal_separator: '.',
+ currency_prefix: '',
+ currency_suffix: '',
+ currency_thousand_separator: ', ',
+ },
+ } );
+
rerender(
-
+
);
expect( screen.queryByText( 'Free' ) ).not.toBeInTheDocument();
expect( screen.getByText( '56.78' ) ).toBeInTheDocument();
} );
+
it( 'should show correct calculator button label if address is complete', () => {
render(
-
+ >
+
+
);
expect(
@@ -323,45 +208,31 @@ describe( 'TotalsShipping', () => {
).toBeInTheDocument();
expect( screen.getByText( 'Change address' ) ).toBeInTheDocument();
} );
+
it( 'should show correct calculator button label if address is incomplete', () => {
baseContextHooks.useStoreCart.mockReturnValue( {
- cartItems: mockPreviewCart.items,
- cartTotals: [ mockPreviewCart.totals ],
- cartCoupons: mockPreviewCart.coupons,
- cartFees: mockPreviewCart.fees,
- cartNeedsShipping: mockPreviewCart.needs_shipping,
- shippingRates: [],
+ ...baseContextHooks.useStoreCart(),
shippingAddress: {
...shippingAddress,
city: '',
country: '',
postcode: '',
},
- billingAddress: mockPreviewCart.billing_address,
- cartHasCalculatedShipping: mockPreviewCart.has_calculated_shipping,
- isLoadingRates: false,
} );
+
render(
-
+ >
+
+
);
expect(
@@ -371,14 +242,10 @@ describe( 'TotalsShipping', () => {
screen.getByText( 'Enter address to check delivery options' )
).toBeInTheDocument();
} );
+
it( 'does show the calculator button when default rates are available and has formatted address', () => {
baseContextHooks.useStoreCart.mockReturnValue( {
- cartItems: mockPreviewCart.items,
- cartTotals: [ mockPreviewCart.totals ],
- cartCoupons: mockPreviewCart.coupons,
- cartFees: mockPreviewCart.fees,
- cartNeedsShipping: mockPreviewCart.needs_shipping,
- shippingRates: mockPreviewCart.shipping_rates,
+ ...baseContextHooks.useStoreCart(),
shippingAddress: {
...shippingAddress,
city: '',
@@ -386,31 +253,21 @@ describe( 'TotalsShipping', () => {
country: 'US',
postcode: '',
},
- billingAddress: mockPreviewCart.billing_address,
- cartHasCalculatedShipping: mockPreviewCart.has_calculated_shipping,
- isLoadingRates: false,
} );
+
render(
-
+ >
+
+
);
expect( screen.queryByText( 'Change address' ) ).toBeInTheDocument();
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/shipping-address.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/shipping-address.tsx
index 2466cb1b847..0a398a7ebbd 100644
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/shipping-address.tsx
+++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/shipping-address.tsx
@@ -4,8 +4,10 @@
import { render, screen } from '@testing-library/react';
import ShippingAddress from '@woocommerce/base-components/cart-checkout/totals/shipping/shipping-address';
import { CART_STORE_KEY, CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
+import { ShippingCalculatorContext } from '@woocommerce/base-components/cart-checkout';
import { dispatch } from '@wordpress/data';
import { previewCart } from '@woocommerce/resource-previews';
+import * as baseContextHooks from '@woocommerce/base-context/hooks';
jest.mock( '@woocommerce/settings', () => {
const originalModule = jest.requireActual( '@woocommerce/settings' );
@@ -25,35 +27,66 @@ jest.mock( '@woocommerce/settings', () => {
},
};
} );
-describe( 'ShippingAddress', () => {
- const testShippingAddress = {
- first_name: 'John',
- last_name: 'Doe',
- company: 'Automattic',
- address_1: '123 Main St',
- address_2: '',
- city: 'San Francisco',
- state: 'CA',
- postcode: '94107',
- country: 'US',
- phone: '555-555-5555',
- };
- it( 'renders ShippingLocation if user does not prefer collection', () => {
+jest.mock( '@woocommerce/base-context/hooks', () => {
+ return {
+ __esModule: true,
+ ...jest.requireActual( '@woocommerce/base-context/hooks' ),
+ useStoreCart: jest.fn(),
+ };
+} );
+
+const shippingAddress = {
+ first_name: 'John',
+ last_name: 'Doe',
+ company: 'Automattic',
+ address_1: '123 Main St',
+ address_2: '',
+ city: 'San Francisco',
+ state: 'CA',
+ postcode: '94107',
+ country: 'US',
+ phone: '555-555-5555',
+};
+
+baseContextHooks.useStoreCart.mockReturnValue( {
+ cartItems: previewCart.items,
+ cartTotals: previewCart.totals,
+ cartCoupons: previewCart.coupons,
+ cartFees: previewCart.fees,
+ cartNeedsShipping: previewCart.needs_shipping,
+ shippingRates: previewCart.shipping_rates,
+ shippingAddress,
+ billingAddress: previewCart.billing_address,
+ cartHasCalculatedShipping: previewCart.has_calculated_shipping,
+ isLoadingRates: false,
+} );
+
+describe( 'ShippingAddress', () => {
+ it( 'Renders shipping address if user does not prefer collection', () => {
render(
-
+
+
+
);
expect( screen.getByText( /Delivers to 94107/ ) ).toBeInTheDocument();
+ expect( screen.getByText( 'Change address' ) ).toBeInTheDocument();
expect(
screen.queryByText( /Collection from/ )
).not.toBeInTheDocument();
+ expect(
+ screen.queryByText( 'Enter address to check delivery options' )
+ ).not.toBeInTheDocument();
} );
- it( 'renders PickupLocation if shopper prefers collection', async () => {
+
+ it( 'Renders pickup location if shopper prefers collection', async () => {
dispatch( CHECKOUT_STORE_KEY ).setPrefersCollection( true );
// Deselect the default selected rate and select pickup_location:1 rate.
@@ -75,12 +108,16 @@ describe( 'ShippingAddress', () => {
dispatch( CART_STORE_KEY ).receiveCart( previewCart );
render(
-
+
+
+
);
expect(
screen.getByText(
@@ -88,4 +125,69 @@ describe( 'ShippingAddress', () => {
)
).toBeInTheDocument();
} );
+
+ it( `renders an address if one is set in the methods metadata`, async () => {
+ dispatch( CHECKOUT_STORE_KEY ).setPrefersCollection( true );
+
+ // Deselect the default selected rate and select pickup_location:1 rate.
+ const currentlySelectedIndex =
+ previewCart.shipping_rates[ 0 ].shipping_rates.findIndex(
+ ( rate ) => rate.selected
+ );
+ previewCart.shipping_rates[ 0 ].shipping_rates[
+ currentlySelectedIndex
+ ].selected = false;
+ const pickupRateIndex =
+ previewCart.shipping_rates[ 0 ].shipping_rates.findIndex(
+ ( rate ) => rate.method_id === 'pickup_location'
+ );
+ previewCart.shipping_rates[ 0 ].shipping_rates[
+ pickupRateIndex
+ ].selected = true;
+
+ dispatch( CART_STORE_KEY ).receiveCart( previewCart );
+
+ render(
);
+ expect(
+ screen.getByText(
+ /Collection from 123 Easy Street, New York, 12345/
+ )
+ ).toBeInTheDocument();
+ } );
+ it( 'renders no address if one is not set in the methods metadata', async () => {
+ dispatch( CHECKOUT_STORE_KEY ).setPrefersCollection( true );
+
+ // Deselect the default selected rate and select pickup_location:1 rate.
+ const currentlySelectedIndex =
+ previewCart.shipping_rates[ 0 ].shipping_rates.findIndex(
+ ( rate ) => rate.selected
+ );
+ previewCart.shipping_rates[ 0 ].shipping_rates[
+ currentlySelectedIndex
+ ].selected = false;
+ const pickupRateIndex =
+ previewCart.shipping_rates[ 0 ].shipping_rates.findIndex(
+ ( rate ) => rate.rate_id === 'pickup_location:2'
+ );
+ previewCart.shipping_rates[ 0 ].shipping_rates[
+ pickupRateIndex
+ ].selected = true;
+
+ // Set the pickup_location metadata value to an empty string in the selected pickup rate.
+ const addressKeyIndex = previewCart.shipping_rates[ 0 ].shipping_rates[
+ pickupRateIndex
+ ].meta_data.findIndex(
+ ( metaData ) => metaData.key === 'pickup_address'
+ );
+ previewCart.shipping_rates[ 0 ].shipping_rates[
+ pickupRateIndex
+ ].meta_data[ addressKeyIndex ].value = '';
+
+ dispatch( CART_STORE_KEY ).receiveCart( previewCart );
+
+ render(
);
+ expect(
+ screen.queryByText( /Collection from / )
+ ).not.toBeInTheDocument();
+ } );
} );
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/shipping-placeholder.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/shipping-placeholder.tsx
deleted file mode 100644
index 914fd73a767..00000000000
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/test/shipping-placeholder.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * External dependencies
- */
-import { screen, render } from '@testing-library/react';
-
-/**
- * Internal dependencies
- */
-import ShippingPlaceholder from '../shipping-placeholder';
-
-const shippingCalculatorID = 'shipping-calculator-form-wrapper';
-
-describe( 'ShippingPlaceholder', () => {
- it( 'should show correct text if showCalculator is false and addressProvided is false', () => {
- const { rerender } = render(
-
- );
- expect(
- screen.getByText( 'Enter address to calculate' )
- ).toBeInTheDocument();
- rerender(
-
- );
- expect(
- screen.getByText( 'Calculated at checkout' )
- ).toBeInTheDocument();
- } );
-
- it( 'should show correct text if showCalculator is false and addressProvided is true', () => {
- render(
-
- );
- expect(
- screen.getByText( 'No available delivery option' )
- ).toBeInTheDocument();
- } );
-} );
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/utils.ts b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/utils.ts
deleted file mode 100644
index 65e7de4f27c..00000000000
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/utils.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * External dependencies
- */
-import { getSetting } from '@woocommerce/settings';
-import type { CartResponseShippingRate } from '@woocommerce/type-defs/cart-response';
-import { hasCollectableRate } from '@woocommerce/base-utils';
-
-/**
- * Searches an array of packages/rates to see if there are actually any rates
- * available.
- *
- * @param {Array} shippingRatePackages An array of packages and rates.
- * @return {boolean} True if a rate exists.
- */
-export const hasShippingRate = (
- shippingRatePackages: CartResponseShippingRate[]
-): boolean => {
- return shippingRatePackages.some(
- ( shippingRatePackage ) => shippingRatePackage.shipping_rates.length
- );
-};
-
-/**
- * Calculates the total shipping value based on store settings.
- */
-export const getTotalShippingValue = ( values: {
- total_shipping: string;
- total_shipping_tax: string;
-} ): number => {
- return getSetting( 'displayCartPricesIncludingTax', false )
- ? parseInt( values.total_shipping, 10 ) +
- parseInt( values.total_shipping_tax, 10 )
- : parseInt( values.total_shipping, 10 );
-};
-
-/**
- * Checks if no shipping methods are available or if all available shipping methods are local pickup
- * only.
- */
-export const areShippingMethodsMissing = (
- hasRates: boolean,
- prefersCollection: boolean | undefined,
- shippingRates: CartResponseShippingRate[]
-) => {
- if ( ! hasRates ) {
- // No shipping methods available
- return true;
- }
-
- // We check for the availability of shipping options if the shopper selected "Shipping"
- if ( ! prefersCollection ) {
- return shippingRates.some(
- ( shippingRatePackage ) =>
- ! shippingRatePackage.shipping_rates.some(
- ( shippingRate ) =>
- ! hasCollectableRate( shippingRate.method_id )
- )
- );
- }
-
- return false;
-};
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/utils.tsx b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/utils.tsx
new file mode 100644
index 00000000000..a6bdfe02650
--- /dev/null
+++ b/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/utils.tsx
@@ -0,0 +1,53 @@
+/**
+ * External dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import {
+ getTotalShippingValue,
+ isPackageRateCollectable,
+} from '@woocommerce/base-utils';
+import {
+ isObject,
+ objectHasProp,
+ CartShippingRate,
+ CartResponseTotals,
+} from '@woocommerce/types';
+
+export const renderShippingTotalValue = ( values: CartResponseTotals ) => {
+ const totalShippingValue = getTotalShippingValue( values );
+ if ( totalShippingValue === 0 ) {
+ return
{ __( 'Free', 'woocommerce' ) } ;
+ }
+ return totalShippingValue;
+};
+
+export const getPickupLocation = (
+ shippingRates: CartShippingRate[]
+): string => {
+ const flattenedRates = ( shippingRates || [] ).flatMap(
+ ( shippingRate ) => shippingRate.shipping_rates
+ );
+
+ const selectedCollectableRate = flattenedRates.find(
+ ( rate ) => rate.selected && isPackageRateCollectable( rate )
+ );
+
+ // If the rate has an address specified in its metadata.
+ if (
+ isObject( selectedCollectableRate ) &&
+ objectHasProp( selectedCollectableRate, 'meta_data' )
+ ) {
+ const selectedRateMetaData = selectedCollectableRate.meta_data.find(
+ ( meta ) => meta.key === 'pickup_address'
+ );
+ if (
+ isObject( selectedRateMetaData ) &&
+ objectHasProp( selectedRateMetaData, 'value' ) &&
+ selectedRateMetaData.value
+ ) {
+ return selectedRateMetaData.value;
+ }
+ }
+
+ return '';
+};
diff --git a/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-checkout-address.ts b/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-checkout-address.ts
index a69c2d22160..9a3ba6c8f70 100644
--- a/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-checkout-address.ts
+++ b/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-checkout-address.ts
@@ -3,7 +3,7 @@
*/
import {
defaultFields,
- AddressFields,
+ FormFields,
ShippingAddress,
BillingAddress,
getSetting,
@@ -30,7 +30,7 @@ interface CheckoutAddress {
setUseShippingAsBilling: ( useShippingAsBilling: boolean ) => void;
setEditingBillingAddress: ( isEditing: boolean ) => void;
setEditingShippingAddress: ( isEditing: boolean ) => void;
- defaultFields: AddressFields;
+ defaultFields: FormFields;
showShippingFields: boolean;
showBillingFields: boolean;
forcedBillingAddress: boolean;
diff --git a/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-show-shipping-total-warning.ts b/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-show-shipping-total-warning.ts
index 69d892a66cb..b25ad38f51c 100644
--- a/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-show-shipping-total-warning.ts
+++ b/plugins/woocommerce-blocks/assets/js/base/context/hooks/use-show-shipping-total-warning.ts
@@ -5,7 +5,7 @@ import { useDispatch, useSelect } from '@wordpress/data';
import { CART_STORE_KEY, CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
import { useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
-import { hasShippingRate } from '@woocommerce/base-components/cart-checkout/totals/shipping/utils';
+import { hasShippingRate } from '@woocommerce/base-utils';
/**
* Internal dependencies
diff --git a/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts b/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts
index f5c61e6bd14..a34d7208e92 100644
--- a/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts
+++ b/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts
@@ -1,12 +1,12 @@
/**
* External dependencies
*/
-import {
- CartShippingPackageShippingRate,
- CartShippingRate,
-} from '@woocommerce/type-defs/cart';
import { getSetting } from '@woocommerce/settings';
import { LOCAL_PICKUP_ENABLED } from '@woocommerce/block-settings';
+import type {
+ CartShippingPackageShippingRate,
+ CartShippingRate,
+} from '@woocommerce/types';
/**
* Get the number of packages in a shippingRates array.
@@ -59,3 +59,97 @@ export const getShippingRatesRateCount = (
return count + shippingPackage.shipping_rates.length;
}, 0 );
};
+
+/**
+ * Searches an array of packages/rates to see if there are actually any rates
+ * available.
+ *
+ * @param {Array} shippingRates An array of packages and rates.
+ * @return {boolean} True if a rate exists.
+ */
+export const hasShippingRate = (
+ shippingRates: CartShippingRate[]
+): boolean => {
+ return shippingRates.some(
+ ( shippingRatesPackage ) =>
+ !! shippingRatesPackage.shipping_rates.length
+ );
+};
+
+/**
+ * Filters an array of packages/rates based on the shopper's preference for collection.
+ */
+export const filterShippingRatesByPrefersCollection = (
+ shippingRates: CartShippingRate[],
+ prefersCollection: boolean
+) => {
+ return shippingRates.map( ( shippingRatesPackage ) => {
+ return {
+ ...shippingRatesPackage,
+ shipping_rates: shippingRatesPackage.shipping_rates.filter(
+ ( rate ) => {
+ const collectableRate = hasCollectableRate(
+ rate.method_id
+ );
+
+ if ( prefersCollection ) {
+ return collectableRate;
+ }
+
+ return ! collectableRate;
+ }
+ ),
+ };
+ } );
+};
+
+/**
+ * Calculates the total shipping value based on store settings.
+ */
+export const getTotalShippingValue = ( values: {
+ total_shipping: string;
+ total_shipping_tax: string;
+} ): number => {
+ return getSetting( 'displayCartPricesIncludingTax', false )
+ ? parseInt( values.total_shipping, 10 ) +
+ parseInt( values.total_shipping_tax, 10 )
+ : parseInt( values.total_shipping, 10 );
+};
+
+/**
+ * Get the names of the selected rates in an array of shipping rates.
+ */
+export const getSelectedShippingRateNames = (
+ shippingRates: CartShippingRate[]
+): string[] => {
+ return shippingRates.flatMap( ( shippingPackage ) => {
+ return shippingPackage.shipping_rates
+ .filter( ( rate ) => rate.selected )
+ .flatMap( ( rate ) => rate.name );
+ } );
+};
+
+export const selectedRatesAreCollectable = (
+ shippingRates: CartShippingRate[]
+): boolean => {
+ return hasShippingRate( shippingRates )
+ ? shippingRates.every( ( shippingPackage ) => {
+ return shippingPackage.shipping_rates.every(
+ ( rate ) =>
+ ! rate.selected || isPackageRateCollectable( rate )
+ );
+ } )
+ : false;
+};
+
+export const allRatesAreCollectable = (
+ shippingRates: CartShippingRate[]
+): boolean => {
+ return hasShippingRate( shippingRates )
+ ? shippingRates.every( ( shippingPackage ) => {
+ return shippingPackage.shipping_rates.every( ( rate ) =>
+ isPackageRateCollectable( rate )
+ );
+ } )
+ : false;
+};
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/payment-methods.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/payment-methods.tsx
similarity index 94%
rename from plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/payment-methods.js
rename to plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/payment-methods.tsx
index 9aa51c084ee..dd452eeb550 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/payment-methods.js
+++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/payment-methods/payment-methods.tsx
@@ -17,10 +17,12 @@ import './style.scss';
/**
* PaymentMethods component.
- *
- * @return {*} The rendered component.
*/
-const PaymentMethods = () => {
+const PaymentMethods = ( {
+ noPaymentMethods =
,
+}: {
+ noPaymentMethods?: JSX.Element | undefined;
+} ) => {
const [ showPaymentMethodsToggle, setShowPaymentMethodsToggle ] =
useState( false );
const {
@@ -50,7 +52,7 @@ const PaymentMethods = () => {
paymentMethodsInitialized &&
Object.keys( availablePaymentMethods ).length === 0
) {
- return
;
+ return noPaymentMethods;
}
// Show payment methods if the toggle is on or if there are no saved payment methods, or if the active saved token is not set.
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx
index bb766723dae..784826df6c3 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout-shared/sidebar-notices/index.tsx
@@ -8,8 +8,6 @@ import {
} from '@wordpress/block-editor';
import { addFilter, hasFilter } from '@wordpress/hooks';
import type { StoreDescriptor } from '@wordpress/data';
-import { NoPaymentMethodsNotice } from '@woocommerce/editor-components/no-payment-methods-notice';
-import { PAYMENT_STORE_KEY } from '@woocommerce/block-data';
import { DefaultNotice } from '@woocommerce/editor-components/default-notice';
import { IncompatibleExtensionsNotice } from '@woocommerce/editor-components/incompatible-extension-notice';
import { useSelect } from '@wordpress/data';
@@ -35,13 +33,7 @@ const withSidebarNotices = createHigherOrderComponent(
isSelected: isBlockSelected,
} = props;
- const {
- isCart,
- isCheckout,
- isPaymentMethodsBlock,
- hasPaymentMethods,
- parentId,
- } = useSelect( ( select ) => {
+ const { isCart, isCheckout, parentId } = useSelect( ( select ) => {
const { getBlockParentsByBlockName, getBlockName } =
select( blockEditorStore );
@@ -82,13 +74,6 @@ const withSidebarNotices = createHigherOrderComponent(
currentBlockName === targetParentBlock
? clientId
: parents[ targetParentBlock ],
- isPaymentMethodsBlock:
- currentBlockName === 'woocommerce/checkout-payment-block',
- hasPaymentMethods:
- select( PAYMENT_STORE_KEY ).paymentMethodsInitialized() &&
- Object.keys(
- select( PAYMENT_STORE_KEY ).getAvailablePaymentMethods()
- ).length > 0,
};
} );
@@ -112,11 +97,6 @@ const withSidebarNotices = createHigherOrderComponent(
/>
-
- { isPaymentMethodsBlock && ! hasPaymentMethods && (
-
- ) }
-
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/block.tsx
index 02d5951711c..eb80546c0bd 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/block.tsx
@@ -1,43 +1,104 @@
/**
* External dependencies
*/
-import { TotalsShipping } from '@woocommerce/base-components/cart-checkout';
-import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
-import { useStoreCart, useEditorContext } from '@woocommerce/base-context/';
-import { TotalsWrapper } from '@woocommerce/blocks-components';
+import { __ } from '@wordpress/i18n';
+import { useState } from '@wordpress/element';
+import {
+ TotalsShipping,
+ ShippingCalculatorButton,
+ ShippingCalculator,
+} from '@woocommerce/base-components/cart-checkout';
+import { ShippingCalculatorContext } from '@woocommerce/base-components/cart-checkout/shipping-calculator/context';
+import { useEditorContext, useStoreCart } from '@woocommerce/base-context';
+import { TotalsWrapper } from '@woocommerce/blocks-checkout';
+import {
+ getShippingRatesPackageCount,
+ selectedRatesAreCollectable,
+ allRatesAreCollectable,
+} from '@woocommerce/base-utils';
import { getSetting } from '@woocommerce/settings';
-import { getShippingRatesPackageCount } from '@woocommerce/base-utils';
-import { select } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { ShippingRateSelector } from './shipping-rate-selector';
const Block = ( { className }: { className: string } ): JSX.Element | null => {
- const { cartTotals, cartNeedsShipping } = useStoreCart();
const { isEditor } = useEditorContext();
+ const { cartNeedsShipping, shippingRates } = useStoreCart();
+ const [ isShippingCalculatorOpen, setIsShippingCalculatorOpen ] =
+ useState( false );
if ( ! cartNeedsShipping ) {
return null;
}
- const shippingRates = select( 'wc/store/cart' ).getShippingRates();
- const shippingRatesPackageCount =
- getShippingRatesPackageCount( shippingRates );
-
- if ( ! shippingRatesPackageCount && isEditor ) {
+ if ( isEditor && getShippingRatesPackageCount( shippingRates ) === 0 ) {
return null;
}
- const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
+ const showCalculator = getSetting< boolean >(
+ 'isShippingCalculatorEnabled',
+ true
+ );
+
+ const hasSelectedCollectionOnly =
+ selectedRatesAreCollectable( shippingRates );
return (
- (
- 'isShippingCalculatorEnabled',
- true
- ) }
- showRateSelector={ true }
- values={ cartTotals }
- currency={ totalsCurrency }
- />
+
+
+ ) : (
+
+ { __(
+ 'Calculated on checkout',
+ 'woocommerce'
+ ) }
+
+ )
+ }
+ collaterals={
+ <>
+ { isShippingCalculatorOpen && (
+
+ ) }
+ { ! isShippingCalculatorOpen && (
+
+ ) }
+ { ! showCalculator &&
+ allRatesAreCollectable( shippingRates ) && (
+
+ { __(
+ 'Delivery options will be calculated during checkout',
+ 'woocommerce'
+ ) }
+
+ ) }
+ >
+ }
+ />
+
);
};
diff --git a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-rate-selector.tsx b/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/shipping-rate-selector.tsx
similarity index 60%
rename from plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-rate-selector.tsx
rename to plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/shipping-rate-selector.tsx
index 9e0022e65eb..8dd4282d213 100644
--- a/plugins/woocommerce-blocks/assets/js/base/components/cart-checkout/totals/shipping/shipping-rate-selector.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/cart/inner-blocks/cart-order-summary-shipping/shipping-rate-selector.tsx
@@ -2,45 +2,35 @@
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
-import type {
- CartResponseShippingAddress,
- CartResponseShippingRate,
-} from '@woocommerce/types';
-import NoticeBanner from '@woocommerce/base-components/notice-banner';
import { createInterpolateElement } from '@wordpress/element';
-/**
- * Internal dependencies
- */
-import ShippingRatesControl from '../../shipping-rates-control';
-import { formatShippingAddress } from '../../../../utils';
-
-export interface ShippingRateSelectorProps {
- hasRates: boolean;
- shippingRates: CartResponseShippingRate[];
- shippingAddress: CartResponseShippingAddress;
- isLoadingRates: boolean;
- isAddressComplete: boolean;
-}
-
-export const ShippingRateSelector = ( {
- hasRates,
- shippingRates,
- shippingAddress,
- isLoadingRates,
+import { ShippingRatesControl } from '@woocommerce/base-components/cart-checkout';
+import NoticeBanner from '@woocommerce/base-components/notice-banner';
+import { useStoreCart } from '@woocommerce/base-context/hooks';
+import {
+ formatShippingAddress,
isAddressComplete,
-}: ShippingRateSelectorProps ): JSX.Element => {
- const legend = hasRates
- ? __( 'Shipping options', 'woocommerce' )
- : __( 'Choose a shipping option', 'woocommerce' );
+} from '@woocommerce/base-utils';
+
+export const ShippingRateSelector = (): JSX.Element => {
+ const { shippingRates, isLoadingRates, shippingAddress } = useStoreCart();
+
+ const hasCompleteAddress = isAddressComplete( shippingAddress, [
+ 'state',
+ 'country',
+ 'postcode',
+ 'city',
+ ] );
return (
- { legend }
+
+ { __( 'Shipping options', 'woocommerce' ) }
+
- { isAddressComplete && (
+ { hasCompleteAddress && (
{
+ return (
+ }
+ label={ label }
+ className="wc-block-checkout__configure-placeholder"
+ >
+
+ { description }
+
+
+ { buttonLabel }
+
+
+ );
+};
+
+export default ConfigurePlaceholder;
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/no-shipping-placeholder/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/checkout/configure-placeholder/style.scss
similarity index 70%
rename from plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/no-shipping-placeholder/style.scss
rename to plugins/woocommerce-blocks/assets/js/blocks/checkout/configure-placeholder/style.scss
index a5e23fedd40..deed836df3c 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/no-shipping-placeholder/style.scss
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/configure-placeholder/style.scss
@@ -1,4 +1,4 @@
-.components-placeholder.wc-block-checkout__no-shipping-placeholder {
+.components-placeholder.wc-block-checkout__configure-placeholder {
margin-bottom: $gap;
* {
@@ -13,7 +13,7 @@
color: $white;
}
- .wc-block-checkout__no-shipping-placeholder-description {
+ .wc-block-checkout__configure-placeholder-description {
display: block;
margin: 0.25em 0 1em 0;
}
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.json b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.json
index 0e01ec44c03..b524ebde66a 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.json
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.json
@@ -16,6 +16,10 @@
"type": "string",
"default": ""
},
+ "disableProductDescriptions": {
+ "type": "boolean",
+ "default": false
+ },
"lock": {
"type": "object",
"default": {
@@ -24,10 +28,8 @@
}
}
},
- "parent": [
- "woocommerce/checkout-order-summary-block"
- ],
+ "parent": [ "woocommerce/checkout-order-summary-block" ],
"textdomain": "woocommerce",
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3
-}
\ No newline at end of file
+}
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.tsx
index 2c3ccab913f..c2b41f0ee2a 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/block.tsx
@@ -5,12 +5,23 @@ import { OrderSummary } from '@woocommerce/base-components/cart-checkout';
import { useStoreCart } from '@woocommerce/base-context/hooks';
import { TotalsWrapper } from '@woocommerce/blocks-components';
-const Block = ( { className = '' }: { className?: string } ): JSX.Element => {
+/**
+ * Internal dependencies
+ */
+import { BlockAttributes } from './edit';
+
+const Block = ( {
+ className = '',
+ disableProductDescriptions = false,
+}: BlockAttributes ): JSX.Element => {
const { cartItems } = useStoreCart();
return (
-
+
);
};
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/edit.tsx
index 5b589f4f095..d5372dc04bd 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/edit.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-cart-items/edit.tsx
@@ -1,26 +1,61 @@
/**
* External dependencies
*/
-import { useBlockProps } from '@wordpress/block-editor';
+import { __ } from '@wordpress/i18n';
+import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
+import { PanelBody, ToggleControl } from '@wordpress/components';
+import { isExperimentalBlocksEnabled } from '@woocommerce/block-settings';
/**
* Internal dependencies
*/
import Block from './block';
+export type BlockAttributes = {
+ className: string;
+ disableProductDescriptions: boolean;
+};
+
export const Edit = ( {
attributes,
+ setAttributes,
}: {
- attributes: {
- className: string;
- };
+ attributes: BlockAttributes;
setAttributes: ( attributes: Record< string, unknown > ) => void;
} ): JSX.Element => {
- const { className } = attributes;
+ const { className, disableProductDescriptions } = attributes;
const blockProps = useBlockProps();
+
return (
-
+ { /* For now this setting can only be enabled if you have experimental features enabled. */ }
+ { isExperimentalBlocksEnabled() && (
+
+
+
+ setAttributes( {
+ disableProductDescriptions:
+ ! disableProductDescriptions,
+ } )
+ }
+ />
+
+
+ ) }
+
);
};
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/block.tsx
index 7ca7678c2b1..e8fbeed254b 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-order-summary-shipping/block.tsx
@@ -1,32 +1,68 @@
/**
* External dependencies
*/
+import { __ } from '@wordpress/i18n';
import { TotalsShipping } from '@woocommerce/base-components/cart-checkout';
-import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
-import { useStoreCart } from '@woocommerce/base-context/hooks';
+import { useStoreCart } from '@woocommerce/base-context';
import { TotalsWrapper } from '@woocommerce/blocks-checkout';
+import { useSelect } from '@wordpress/data';
+import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data';
+import {
+ filterShippingRatesByPrefersCollection,
+ isAddressComplete,
+ selectedRatesAreCollectable,
+} from '@woocommerce/base-utils';
const Block = ( {
className = '',
}: {
className?: string;
} ): JSX.Element | null => {
- const { cartTotals, cartNeedsShipping } = useStoreCart();
+ const { cartNeedsShipping, shippingRates, shippingAddress } =
+ useStoreCart();
+ const prefersCollection = useSelect( ( select ) =>
+ select( CHECKOUT_STORE_KEY ).prefersCollection()
+ );
if ( ! cartNeedsShipping ) {
return null;
}
- const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
+ const hasSelectedCollectionOnly = selectedRatesAreCollectable(
+ filterShippingRatesByPrefersCollection(
+ shippingRates,
+ prefersCollection ?? false
+ )
+ );
+
+ const hasCompleteAddress = isAddressComplete( shippingAddress, [
+ 'state',
+ 'country',
+ 'postcode',
+ 'city',
+ ] );
return (
+ { hasCompleteAddress
+ ? __(
+ 'No available delivery option',
+ 'woocommerce'
+ )
+ : __(
+ 'Enter address to calculate',
+ 'woocommerce'
+ ) }
+
+ }
/>
);
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/block.tsx
index c204a044262..e68704bc635 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/block.tsx
@@ -3,8 +3,12 @@
*/
import { PaymentMethods } from '../../../cart-checkout-shared/payment-methods';
-const Block = (): JSX.Element | null => {
- return ;
+const Block = ( {
+ noPaymentMethods,
+}: {
+ noPaymentMethods?: JSX.Element | undefined;
+} ): JSX.Element | null => {
+ return ;
};
export default Block;
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/edit.tsx
index 820c7b5ed5e..9c9d4b408e9 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/edit.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-payment-block/edit.tsx
@@ -5,6 +5,7 @@ import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
import { PanelBody, ExternalLink } from '@wordpress/components';
+import { payment } from '@wordpress/icons';
import { ADMIN_URL, getSetting } from '@woocommerce/settings';
import ExternalLinkCard from '@woocommerce/editor-components/external-link-card';
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
@@ -24,6 +25,7 @@ import {
AdditionalFieldsContent,
} from '../../form-step';
import Block from './block';
+import ConfigurePlaceholder from '../../configure-placeholder';
export const Edit = ( {
attributes,
@@ -119,7 +121,23 @@ export const Edit = ( {
) }
-
+
+ }
+ />
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx
index 13633478b0c..608e23732a9 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/block.tsx
@@ -60,7 +60,26 @@ const renderShippingRatesControlOption = (
};
};
-const Block = ( { noShippingPlaceholder = null } ): ReactElement | null => {
+const NoShippingAddressMessage = () => {
+ return (
+
+ { __(
+ 'Enter a shipping address to view shipping options.',
+ 'woocommerce'
+ ) }
+
+ );
+};
+
+const Block = ( {
+ noShippingPlaceholder = null,
+}: {
+ noShippingPlaceholder?: ReactElement | null;
+} ) => {
const { isEditor } = useEditorContext();
const {
@@ -95,14 +114,7 @@ const Block = ( { noShippingPlaceholder = null } ): ReactElement | null => {
getShippingRatesPackageCount( shippingRates );
if ( ! hasCalculatedShipping && ! shippingRatesPackageCount ) {
- return (
-
- { __(
- 'Shipping options will be displayed here after entering your full shipping address.',
- 'woocommerce'
- ) }
-
- );
+ return ;
}
const addressComplete = isAddressComplete( shippingAddress );
@@ -124,15 +136,12 @@ const Block = ( { noShippingPlaceholder = null } ): ReactElement | null => {
status="warning"
>
{ __(
- 'There are no shipping options available. Please check your shipping address.',
+ 'No shipping options are available for this address. Please verify the address is correct or try a different address.',
'woocommerce'
) }
) : (
- __(
- 'Add a shipping address to view shipping options.',
- 'woocommerce'
- )
+
) }
>
}
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/edit.tsx
index 6845bfe7e78..c690f6d1a31 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/edit.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/edit.tsx
@@ -5,6 +5,7 @@ import clsx from 'clsx';
import { __ } from '@wordpress/i18n';
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
import { PanelBody, ExternalLink } from '@wordpress/components';
+import { shipping } from '@wordpress/icons';
import { ADMIN_URL, getSetting } from '@woocommerce/settings';
import ExternalLinkCard from '@woocommerce/editor-components/external-link-card';
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
@@ -19,7 +20,7 @@ import {
AdditionalFields,
AdditionalFieldsContent,
} from '../../form-step';
-import NoShippingPlaceholder from './no-shipping-placeholder';
+import ConfigurePlaceholder from '../../configure-placeholder';
import Block from './block';
import './editor.scss';
@@ -126,7 +127,23 @@ export const Edit = ( {
) }
- } />
+
+ }
+ />
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/no-shipping-placeholder/index.js b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/no-shipping-placeholder/index.js
deleted file mode 100644
index 501a8eddc73..00000000000
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/no-shipping-placeholder/index.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * External dependencies
- */
-import { __ } from '@wordpress/i18n';
-import { Placeholder, Button } from '@wordpress/components';
-import { Icon, shipping } from '@wordpress/icons';
-import { ADMIN_URL } from '@woocommerce/settings';
-
-/**
- * Internal dependencies
- */
-import './style.scss';
-
-const NoShippingPlaceholder = () => {
- return (
- }
- label={ __( 'Shipping options', 'woocommerce' ) }
- className="wc-block-checkout__no-shipping-placeholder"
- >
-
- { __(
- 'Your store does not have any Shipping Options configured. Once you have added your Shipping Options they will appear here.',
- 'woocommerce'
- ) }
-
-
- { __( 'Configure Shipping Options', 'woocommerce' ) }
-
-
- );
-};
-
-export default NoShippingPlaceholder;
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/style.scss
index bb950600655..72379d3530b 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/style.scss
+++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-methods-block/style.scss
@@ -11,4 +11,11 @@
.wc-block-components-shipping-rates-control__no-results-notice {
margin: em($gap-small) 0;
}
+
+ .wc-block-components-shipping-rates-control__no-shipping-address-message {
+ background-color: $gray-200;
+ color: $gray-700;
+ padding: em($gap-large);
+ text-align: center;
+ }
}
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.tsx
index d947a80bdc0..4d93aea271f 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/block.tsx
@@ -12,8 +12,12 @@ import {
PanelBody,
ToggleControl,
Placeholder,
+
+ // @ts-expect-error - no types.
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToggleGroupControl as ToggleGroupControl,
+
+ // @ts-expect-error - no types.
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
} from '@wordpress/components';
@@ -72,6 +76,7 @@ const ProductCategoriesBlock = ( {
>
setAttributes( {
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/edit.tsx
index eaf56523e24..f661957ce3a 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/edit.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/edit.tsx
@@ -10,7 +10,9 @@ import Block from './block';
import './editor.scss';
import type { ProductCategoriesBlockProps } from './types';
-export const Edit = ( props: ProductCategoriesBlockProps ): JSX.Element => {
+export default function ProductCategoriesEdit(
+ props: ProductCategoriesBlockProps
+): JSX.Element {
const blockProps = useBlockProps();
return (
@@ -18,4 +20,4 @@ export const Edit = ( props: ProductCategoriesBlockProps ): JSX.Element => {
);
-};
+}
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/index.tsx
index f3f076d69cb..ae9ccf2ffbe 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/product-categories/index.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/product-categories/index.tsx
@@ -7,11 +7,11 @@ import { Icon, listView } from '@wordpress/icons';
/**
* Internal dependencies
*/
-import './editor.scss';
import metadata from './block.json';
-import './style.scss';
-import { Edit } from './edit';
+import Edit from './edit';
import type { ProductCategoriesIndexProps } from './types';
+import './editor.scss';
+import './style.scss';
registerBlockType( metadata, {
icon: {
diff --git a/plugins/woocommerce-blocks/assets/js/blocks/product-elements/add-to-cart-form/edit.tsx b/plugins/woocommerce-blocks/assets/js/blocks/product-elements/add-to-cart-form/edit.tsx
index 211aea918b4..0bc2c4765db 100644
--- a/plugins/woocommerce-blocks/assets/js/blocks/product-elements/add-to-cart-form/edit.tsx
+++ b/plugins/woocommerce-blocks/assets/js/blocks/product-elements/add-to-cart-form/edit.tsx
@@ -9,6 +9,8 @@ import { BlockEditProps } from '@wordpress/blocks';
import { Disabled, Tooltip } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { isSiteEditorPage } from '@woocommerce/utils';
+import { getSettingWithCoercion } from '@woocommerce/settings';
+import { isBoolean } from '@woocommerce/types';
/**
* Internal dependencies
@@ -26,8 +28,15 @@ export interface Attributes {
const Edit = ( props: BlockEditProps< Attributes > ) => {
const { setAttributes } = props;
+ const isStepperLayoutFeatureEnabled = getSettingWithCoercion(
+ 'isStepperLayoutFeatureEnabled',
+ false,
+ isBoolean
+ );
+
const quantitySelectorStyleClass =
- props.attributes.quantitySelectorStyle === QuantitySelectorStyle.Input
+ props.attributes.quantitySelectorStyle ===
+ QuantitySelectorStyle.Input || ! isStepperLayoutFeatureEnabled
? 'wc-block-add-to-cart-form--input'
: 'wc-block-add-to-cart-form--stepper';
@@ -52,10 +61,14 @@ const Edit = ( props: BlockEditProps< Attributes > ) => {
return (
<>
-