From 2147e8a22a350e259485b3765be52e0db79e718f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Thu, 12 Mar 2020 10:41:35 +0100 Subject: [PATCH] Add checkout sidebar (https://github.com/woocommerce/woocommerce-blocks/pull/1921) --- .../base/components/sidebar-layout/index.js | 8 + .../js/base/components/sidebar-layout/main.js | 14 + .../sidebar-layout/sidebar-layout.js | 14 + .../base/components/sidebar-layout/sidebar.js | 14 + .../base/components/sidebar-layout/style.scss | 86 ++++ .../totals/totals-coupon-code-input/index.js | 3 +- .../totals/totals-shipping-item/index.js | 14 +- .../cart-checkout/cart/full-cart/index.js | 18 +- .../cart-checkout/cart/full-cart/style.scss | 81 +--- .../js/blocks/cart-checkout/checkout/block.js | 438 ++++++++++-------- .../js/blocks/cart-checkout/checkout/edit.js | 6 +- .../blocks/cart-checkout/checkout/frontend.js | 14 +- .../blocks/cart-checkout/checkout/sidebar.js | 71 +++ .../assets/js/data/cart/reducers.js | 20 +- .../assets/js/data/cart/selectors.js | 20 +- .../src/BlockTypes/Cart.php | 6 +- 16 files changed, 507 insertions(+), 320 deletions(-) create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/index.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/main.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar-layout.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.js create mode 100644 plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/style.scss create mode 100644 plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/sidebar.js diff --git a/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/index.js b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/index.js new file mode 100644 index 00000000000..c281d8a2f3a --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/index.js @@ -0,0 +1,8 @@ +/** + * Internal dependencies + */ +import './style.scss'; + +export { default as Sidebar } from './sidebar'; +export { default as Main } from './main'; +export { default as SidebarLayout } from './sidebar-layout'; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/main.js b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/main.js new file mode 100644 index 00000000000..a7dfe9658f5 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/main.js @@ -0,0 +1,14 @@ +/** + * External dependencies + */ +import classNames from 'classnames'; + +const Main = ( { children, className } ) => { + return ( +
+ { children } +
+ ); +}; + +export default Main; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar-layout.js b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar-layout.js new file mode 100644 index 00000000000..e510447e1c9 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar-layout.js @@ -0,0 +1,14 @@ +/** + * External dependencies + */ +import classNames from 'classnames'; + +const SidebarLayout = ( { children, className } ) => { + return ( +
+ { children } +
+ ); +}; + +export default SidebarLayout; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.js b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.js new file mode 100644 index 00000000000..41114e5acef --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/sidebar.js @@ -0,0 +1,14 @@ +/** + * External dependencies + */ +import classNames from 'classnames'; + +const Sidebar = ( { children, className } ) => { + return ( +
+ { children } +
+ ); +}; + +export default Sidebar; diff --git a/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/style.scss b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/style.scss new file mode 100644 index 00000000000..88c938efd6a --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/base/components/sidebar-layout/style.scss @@ -0,0 +1,86 @@ +.wc-block-sidebar-layout { + display: flex; + flex-wrap: wrap; + margin: 0 (-$gap) $gap; + + .wc-block-main { + flex: 1 0 65%; + margin: 0; + padding: 0 $gap; + min-width: 500px; + } + + .wc-block-sidebar { + flex: 1 1 35%; + margin: 0; + max-width: 35%; + padding: 0 $gap; + + // Reset Gutenberg styles when used in the sidebar. + .components-panel__body { + border-top: 1px solid $core-grey-light-600; + border-bottom: 1px solid $core-grey-light-600; + + &.is-opened { + padding-left: 0; + padding-right: 0; + + > .components-panel__body-title { + margin-left: 0; + margin-right: 0; + } + } + + > .components-panel__body-title, + .components-panel__body-toggle { + &, + &:hover, + &:focus, + &:active { + background-color: transparent; + color: inherit; + } + } + + .components-panel__body-toggle { + font-weight: normal; + font-size: inherit; + padding-left: 0; + padding-right: 36px; + + &.components-button, + &.components-button:focus:not(:disabled):not([aria-disabled="true"]) { + color: inherit; + } + } + } + } +} + +@include breakpoint( "<782px" ) { + .wc-block-sidebar-layout { + display: block; + margin: 0 0 $gap; + + .wc-block-main { + padding: 0; + flex: none; + min-width: 200px; + } + .wc-block-sidebar { + padding: 0; + flex: none; + max-width: 100%; + + // Reset (remove) totals "card" styling on mobile. + .components-card { + box-shadow: none; + border: none; + } + .components-card__body { + border: none; + padding: 0; + } + } + } +} diff --git a/plugins/woocommerce-blocks/assets/js/base/components/totals/totals-coupon-code-input/index.js b/plugins/woocommerce-blocks/assets/js/base/components/totals/totals-coupon-code-input/index.js index 0f01424959c..3d8b673cb95 100644 --- a/plugins/woocommerce-blocks/assets/js/base/components/totals/totals-coupon-code-input/index.js +++ b/plugins/woocommerce-blocks/assets/js/base/components/totals/totals-coupon-code-input/index.js @@ -19,6 +19,7 @@ import LoadingMask from '../../loading-mask'; const TotalsCouponCodeInput = ( { instanceId, isLoading = false, + initialOpen, onSubmit = () => {}, } ) => { const [ couponValue, setCouponValue ] = useState( '' ); @@ -49,7 +50,7 @@ const TotalsCouponCodeInput = ( { htmlFor={ `wc-block-coupon-code__input-${ instanceId }` } /> } - initialOpen={ true } + initialOpen={ initialOpen } > - - + { shippingAddress && ( + + ) } + { updateShippingAddress && shippingAddress && ( + + ) } } label={ __( 'Shipping', 'woo-gutenberg-products-block' ) } diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/index.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/index.js index cd9154a17fe..f38c88d949b 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/index.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/index.js @@ -25,6 +25,11 @@ import FormattedMonetaryAmount from '@woocommerce/base-components/formatted-mone import { decodeEntities } from '@wordpress/html-entities'; import { useStoreCartCoupons, useShippingRates } from '@woocommerce/base-hooks'; import classnames from 'classnames'; +import { + Sidebar, + SidebarLayout, + Main, +} from '@woocommerce/base-components/sidebar-layout'; /** * Internal dependencies @@ -118,15 +123,15 @@ const Cart = ( { } ); return ( -
-
+ +
-
-
+ +

@@ -183,6 +188,7 @@ const Cart = ( { { COUPONS_ENABLED && ( ) } @@ -193,8 +199,8 @@ const Cart = ( { -

-
+ + ); }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/style.scss index 468bcd5c042..26df354ab7e 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/style.scss +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/cart/full-cart/style.scss @@ -1,21 +1,6 @@ .wc-block-cart { color: $core-grey-dark-600; - display: flex; - flex-wrap: wrap; - margin: 0 (-$gap) $gap; - .wc-block-cart__main { - flex: 1 0 65%; - margin: 0; - padding: 0 $gap; - min-width: 500px; - } - .wc-block-cart__sidebar { - flex: 1 1 35%; - margin: 0; - max-width: 35%; - padding: 0 $gap; - } .wc-block-cart__item-count { float: right; } @@ -275,75 +260,13 @@ table.wc-block-cart-items { display: flex; } -// Reset Gutenberg styles when used in the sidebar. -.wc-block-cart__sidebar { - .components-panel__body { - border-top: 1px solid $core-grey-light-600; - border-bottom: 1px solid $core-grey-light-600; - - &.is-opened { - padding-left: 0; - padding-right: 0; - - > .components-panel__body-title { - margin-left: 0; - margin-right: 0; - } - } - - > .components-panel__body-title, - .components-panel__body-toggle { - &, - &:hover, - &:focus, - &:active { - background-color: transparent; - color: inherit; - } - } - - .components-panel__body-toggle { - font-weight: normal; - font-size: inherit; - padding-left: 0; - padding-right: 36px; - - &.components-button, - &.components-button:focus:not(:disabled):not([aria-disabled="true"]) { - color: inherit; - } - } - } -} - // Mobile styles. @include breakpoint( "<782px" ) { - .wc-block-cart:not(.wc-block-cart--is-loading):not(.wc-block-cart--skeleton) { - display: block; - margin: 0 0 $gap; - .wc-block-cart__main { - padding: 0; - flex: none; - min-width: 200px; - } - .wc-block-cart__sidebar { - padding: 0; - flex: none; - max-width: 100%; - + .wc-block-cart { + .wc-block-sidebar { .wc-block-cart__totals-title { display: none; } - - // Reset (remove) totals "card" styling on mobile. - .components-card { - box-shadow: none; - border: none; - } - .components-card__body { - border: none; - padding: 0; - } } } table.wc-block-cart-items { diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js index 86d14cc1554..38b70e164f8 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/block.js @@ -24,14 +24,26 @@ import { import { SHIPPING_ENABLED } from '@woocommerce/block-settings'; import { decodeEntities } from '@wordpress/html-entities'; import { useShippingRates } from '@woocommerce/base-hooks'; +import { + Sidebar, + SidebarLayout, + Main, +} from '@woocommerce/base-components/sidebar-layout'; // @todo /** * Internal dependencies */ +import CheckoutSidebar from './sidebar.js'; import './style.scss'; import '../../../payment-methods-demo'; -const Block = ( { attributes, isEditor = false, shippingRates = [] } ) => { +const Block = ( { + attributes, + cartCoupons = [], + cartTotals = {}, + isEditor = false, + shippingRates = [], +} ) => { const [ selectedShippingRate, setSelectedShippingRate ] = useState( {} ); const [ contactFields, setContactFields ] = useState( {} ); const [ shouldSavePayment, setShouldSavePayment ] = useState( true ); @@ -80,228 +92,248 @@ const Block = ( { attributes, isEditor = false, shippingRates = [] } ) => { return ( - - - ( - - { __( - 'Already have an account? ', - 'woo-gutenberg-products-block' - ) } - - { __( - 'Log in.', - 'woo-gutenberg-products-block' - ) } - - - ) } - > - - setContactFields( { - ...contactFields, - email: newValue, - } ) - } - required={ true } - /> - - setContactFields( { - ...contactFields, - keepUpdated: ! contactFields.keepUpdated, - } ) - } - /> - - { SHIPPING_ENABLED && ( - - - { attributes.showPhoneField && ( - - setShippingFields( { - ...shippingFields, - phone: newValue, - } ) - } - required={ attributes.requirePhoneField } - /> - ) } - - setUseShippingAsBilling( isChecked ) - } - /> - - ) } - { showBillingFields && ( - - - - ) } - { SHIPPING_ENABLED && - ( shippingRates.length === 0 && isEditor ? ( - - ) : ( + +
+ + ( + + { __( + 'Already have an account? ', + 'woo-gutenberg-products-block' + ) } + + { __( + 'Log in.', + 'woo-gutenberg-products-block' + ) } + + + ) } > - + setContactFields( { + ...contactFields, + email: newValue, + } ) } - shippingRates={ shippingRates } - shippingRatesLoading={ shippingRatesLoading } + required={ true } /> - - setSelectedShippingRate( { - ...selectedShippingRate, - orderNote: ! selectedShippingRate.orderNote, + setContactFields( { + ...contactFields, + keepUpdated: ! contactFields.keepUpdated, } ) } /> - ) ) } - - - { /*@todo this should be something the payment method controls*/ } - + + { attributes.showPhoneField && ( + + setShippingFields( { + ...shippingFields, + phone: newValue, + } ) + } + required={ + attributes.requirePhoneField + } + /> + ) } + + setUseShippingAsBilling( isChecked ) + } + /> + ) } - checked={ shouldSavePayment } - onChange={ () => - setShouldSavePayment( ! shouldSavePayment ) - } + { showBillingFields && ( + + + + ) } + { SHIPPING_ENABLED && + ( shippingRates.length === 0 && isEditor ? ( + + ) : ( + + + + + setSelectedShippingRate( { + ...selectedShippingRate, + orderNote: ! selectedShippingRate.orderNote, + } ) + } + /> + + ) ) } + + + { /*@todo this should be something the payment method controls*/ } + + setShouldSavePayment( ! shouldSavePayment ) + } + /> + + { attributes.showPolicyLinks && } + +
+ + - - { attributes.showPolicyLinks && } -
+ +
); }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js index a4e1bcb2265..fab21f233ac 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/edit.js @@ -3,7 +3,10 @@ */ import { __ } from '@wordpress/i18n'; import { withFeedbackPrompt } from '@woocommerce/block-hocs'; -import { previewShippingRates } from '@woocommerce/resource-previews'; +import { + previewCart, + previewShippingRates, +} from '@woocommerce/resource-previews'; import { InspectorControls } from '@wordpress/block-editor'; import { PanelBody, @@ -216,6 +219,7 @@ const CheckoutEditor = ( { attributes, setAttributes } ) => { > { - const { cartErrors, shippingRates } = useStoreCart(); + const { + cartCoupons, + cartErrors, + cartTotals, + shippingRates, + } = useStoreCart(); if ( cartErrors && cartErrors.length > 0 ) { throw new Error( cartErrors[ 0 ].message ); @@ -50,7 +55,12 @@ const CheckoutFrontend = ( props ) => { ) } showErrorMessage={ CURRENT_USER_IS_ADMIN } > - + ); }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/sidebar.js b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/sidebar.js new file mode 100644 index 00000000000..d0b6eaa1682 --- /dev/null +++ b/plugins/woocommerce-blocks/assets/js/blocks/cart-checkout/checkout/sidebar.js @@ -0,0 +1,71 @@ +/** + * External dependencies + */ +import { + SubtotalsItem, + TotalsFeesItem, + TotalsCouponCodeInput, + TotalsDiscountItem, + TotalsFooterItem, + TotalsShippingItem, + TotalsTaxesItem, +} from '@woocommerce/base-components/totals'; +import { getCurrencyFromPriceResponse } from '@woocommerce/base-utils'; +import { + COUPONS_ENABLED, + DISPLAY_CART_PRICES_INCLUDING_TAX, +} from '@woocommerce/block-settings'; +import { useStoreCartCoupons } from '@woocommerce/base-hooks'; + +const CheckoutSidebar = ( { + cartCoupons = [], + cartTotals = {}, + shippingRates, +} ) => { + const { + applyCoupon, + removeCoupon, + isApplyingCoupon, + isRemovingCoupon, + } = useStoreCartCoupons(); + const shippingAddress = shippingRates[ 0 ]?.destination; + const totalsCurrency = getCurrencyFromPriceResponse( cartTotals ); + + return ( + <> + + + + + { ! DISPLAY_CART_PRICES_INCLUDING_TAX && ( + + ) } + { COUPONS_ENABLED && ( + + ) } + + + ); +}; + +export default CheckoutSidebar; diff --git a/plugins/woocommerce-blocks/assets/js/data/cart/reducers.js b/plugins/woocommerce-blocks/assets/js/data/cart/reducers.js index 52fde20f145..99bf4467ed6 100644 --- a/plugins/woocommerce-blocks/assets/js/data/cart/reducers.js +++ b/plugins/woocommerce-blocks/assets/js/data/cart/reducers.js @@ -59,16 +59,16 @@ const reducer = ( currency_thousand_separator: ',', currency_prefix: '', currency_suffix: '', - 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, + 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: [], }, }, diff --git a/plugins/woocommerce-blocks/assets/js/data/cart/selectors.js b/plugins/woocommerce-blocks/assets/js/data/cart/selectors.js index ed5f9ff19c7..67ab1f2d8b8 100644 --- a/plugins/woocommerce-blocks/assets/js/data/cart/selectors.js +++ b/plugins/woocommerce-blocks/assets/js/data/cart/selectors.js @@ -37,16 +37,16 @@ export const getCartTotals = ( state ) => { currency_thousand_separator: ',', currency_prefix: '', currency_suffix: '', - 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, + 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: [], } ); diff --git a/plugins/woocommerce-blocks/src/BlockTypes/Cart.php b/plugins/woocommerce-blocks/src/BlockTypes/Cart.php index ee2a58fa8f1..6b9291956b5 100644 --- a/plugins/woocommerce-blocks/src/BlockTypes/Cart.php +++ b/plugins/woocommerce-blocks/src/BlockTypes/Cart.php @@ -80,8 +80,8 @@ class Cart extends AbstractBlock { */ protected function get_skeleton() { return ' -