rebase from live enviornment
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { filledCart, removeCart } from '@woocommerce/icons';
|
||||
|
||||
export const blockName = 'woocommerce/cart';
|
||||
export const blockAttributes = {
|
||||
isPreview: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
},
|
||||
currentView: {
|
||||
type: 'string',
|
||||
default: 'woocommerce/filled-cart-block',
|
||||
source: 'readonly', // custom source to prevent saving to post content
|
||||
},
|
||||
editorViews: {
|
||||
type: 'object',
|
||||
default: [
|
||||
{
|
||||
view: 'woocommerce/filled-cart-block',
|
||||
label: __( 'Filled Cart', 'woocommerce' ),
|
||||
icon: <Icon icon={ filledCart } />,
|
||||
},
|
||||
{
|
||||
view: 'woocommerce/empty-cart-block',
|
||||
label: __( 'Empty Cart', 'woocommerce' ),
|
||||
icon: <Icon icon={ removeCart } />,
|
||||
},
|
||||
],
|
||||
},
|
||||
hasDarkControls: {
|
||||
type: 'boolean',
|
||||
default: getSetting( 'hasDarkEditorStyleSupport', false ),
|
||||
},
|
||||
// Deprecated - here for v1 migration support
|
||||
isShippingCalculatorEnabled: {
|
||||
type: 'boolean',
|
||||
default: getSetting( 'isShippingCalculatorEnabled', true ),
|
||||
},
|
||||
checkoutPageId: {
|
||||
type: 'number',
|
||||
default: 0,
|
||||
},
|
||||
showRateAfterTaxName: {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
},
|
||||
align: {
|
||||
type: 'string',
|
||||
default: 'wide',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
import { useEffect } from '@wordpress/element';
|
||||
import LoadingMask from '@woocommerce/base-components/loading-mask';
|
||||
import { CURRENT_USER_IS_ADMIN } from '@woocommerce/settings';
|
||||
import BlockErrorBoundary from '@woocommerce/base-components/block-error-boundary';
|
||||
import { translateJQueryEventToNative } from '@woocommerce/base-utils';
|
||||
import withScrollToTop from '@woocommerce/base-hocs/with-scroll-to-top';
|
||||
import {
|
||||
CartEventsProvider,
|
||||
CartProvider,
|
||||
noticeContexts,
|
||||
} from '@woocommerce/base-context';
|
||||
import { SlotFillProvider } from '@woocommerce/blocks-checkout';
|
||||
import { StoreNoticesContainer } from '@woocommerce/blocks-components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { CartBlockContext } from './context';
|
||||
import './style.scss';
|
||||
|
||||
const reloadPage = () => void window.location.reload( true );
|
||||
|
||||
const Cart = ( { children, attributes = {} } ) => {
|
||||
const { cartIsLoading } = useStoreCart();
|
||||
const { hasDarkControls } = attributes;
|
||||
|
||||
return (
|
||||
<LoadingMask showSpinner={ true } isLoading={ cartIsLoading }>
|
||||
<CartBlockContext.Provider
|
||||
value={ {
|
||||
hasDarkControls,
|
||||
} }
|
||||
>
|
||||
{ children }
|
||||
</CartBlockContext.Provider>
|
||||
</LoadingMask>
|
||||
);
|
||||
};
|
||||
|
||||
const ScrollOnError = ( { scrollToTop } ) => {
|
||||
useEffect( () => {
|
||||
// Make it so we can read jQuery events triggered by WC Core elements.
|
||||
const removeJQueryAddedToCartEvent = translateJQueryEventToNative(
|
||||
'added_to_cart',
|
||||
'wc-blocks_added_to_cart'
|
||||
);
|
||||
|
||||
document.body.addEventListener(
|
||||
'wc-blocks_added_to_cart',
|
||||
scrollToTop
|
||||
);
|
||||
|
||||
return () => {
|
||||
removeJQueryAddedToCartEvent();
|
||||
|
||||
document.body.removeEventListener(
|
||||
'wc-blocks_added_to_cart',
|
||||
scrollToTop
|
||||
);
|
||||
};
|
||||
}, [ scrollToTop ] );
|
||||
|
||||
return null;
|
||||
};
|
||||
const Block = ( { attributes, children, scrollToTop } ) => (
|
||||
<BlockErrorBoundary
|
||||
header={ __(
|
||||
'Something went wrong. Please contact us for assistance.',
|
||||
'woocommerce'
|
||||
) }
|
||||
text={ __(
|
||||
'The cart has encountered an unexpected error. If the error persists, please get in touch with us for help.',
|
||||
'woocommerce'
|
||||
) }
|
||||
button={
|
||||
<button className="wc-block-button" onClick={ reloadPage }>
|
||||
{ __( 'Reload the page', 'woocommerce' ) }
|
||||
</button>
|
||||
}
|
||||
showErrorMessage={ CURRENT_USER_IS_ADMIN }
|
||||
>
|
||||
<StoreNoticesContainer context={ noticeContexts.CART } />
|
||||
<SlotFillProvider>
|
||||
<CartProvider>
|
||||
<CartEventsProvider>
|
||||
<Cart attributes={ attributes }>{ children }</Cart>
|
||||
<ScrollOnError scrollToTop={ scrollToTop } />
|
||||
</CartEventsProvider>
|
||||
</CartProvider>
|
||||
</SlotFillProvider>
|
||||
</BlockErrorBoundary>
|
||||
);
|
||||
export default withScrollToTop( Block );
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
InnerBlockLayoutContextProvider,
|
||||
ProductDataContextProvider,
|
||||
} from '@woocommerce/shared-context';
|
||||
import { ProductResponseItem } from '@woocommerce/types';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Block as ProductImage } from '../../../atomic/blocks/product-elements/image/block';
|
||||
import { Block as ProductName } from '../../../atomic/blocks/product-elements/title/block';
|
||||
import { Block as ProductRating } from '../../../atomic/blocks/product-elements/rating/block';
|
||||
import { Block as ProductSaleBadge } from '../../../atomic/blocks/product-elements/sale-badge/block';
|
||||
import { Block as ProductPrice } from '../../../atomic/blocks/product-elements/price/block';
|
||||
import { Block as ProductButton } from '../../../atomic/blocks/product-elements/button/block';
|
||||
import { ImageSizing } from '../../../atomic/blocks/product-elements/image/types';
|
||||
|
||||
interface CrossSellsProductProps {
|
||||
product: ProductResponseItem;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
const CartCrossSellsProduct = ( {
|
||||
product,
|
||||
}: CrossSellsProductProps ): JSX.Element => {
|
||||
return (
|
||||
<div className="cross-sells-product">
|
||||
<InnerBlockLayoutContextProvider
|
||||
parentName={ 'woocommerce/cart-cross-sells-block' }
|
||||
parentClassName={ 'wp-block-cart-cross-sells-product' }
|
||||
>
|
||||
<ProductDataContextProvider
|
||||
// Setting isLoading to false, given this parameter is required.
|
||||
isLoading={ false }
|
||||
product={ product }
|
||||
>
|
||||
<div>
|
||||
<ProductImage
|
||||
className={ '' }
|
||||
showSaleBadge={ false }
|
||||
productId={ product.id }
|
||||
showProductLink={ false }
|
||||
saleBadgeAlign={ 'left' }
|
||||
imageSizing={ ImageSizing.SINGLE }
|
||||
isDescendentOfQueryLoop={ false }
|
||||
/>
|
||||
<ProductName
|
||||
align={ '' }
|
||||
headingLevel={ 3 }
|
||||
showProductLink={ true }
|
||||
/>
|
||||
<ProductRating />
|
||||
<ProductSaleBadge
|
||||
productId={ product.id }
|
||||
align={ 'left' }
|
||||
/>
|
||||
<ProductPrice />
|
||||
</div>
|
||||
<ProductButton />
|
||||
</ProductDataContextProvider>
|
||||
</InnerBlockLayoutContextProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CartCrossSellsProduct;
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { ProductResponseItem } from '@woocommerce/types';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import CartCrossSellsProduct from './cart-cross-sells-product';
|
||||
|
||||
interface CrossSellsProductListProps {
|
||||
products: ProductResponseItem[];
|
||||
className?: string | undefined;
|
||||
columns: number;
|
||||
}
|
||||
|
||||
const CartCrossSellsProductList = ( {
|
||||
products,
|
||||
columns,
|
||||
}: CrossSellsProductListProps ): JSX.Element => {
|
||||
const crossSellsProducts = products.map( ( product, i ) => {
|
||||
if ( i >= columns ) return null;
|
||||
|
||||
return (
|
||||
<CartCrossSellsProduct
|
||||
// Setting isLoading to false, given this parameter is required.
|
||||
isLoading={ false }
|
||||
product={ product }
|
||||
key={ product.id }
|
||||
/>
|
||||
);
|
||||
} );
|
||||
|
||||
return <div>{ crossSellsProducts }</div>;
|
||||
};
|
||||
|
||||
export default CartCrossSellsProductList;
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { createContext, useContext } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Context consumed by inner blocks.
|
||||
*/
|
||||
export type CartBlockContextProps = {
|
||||
hasDarkControls: boolean;
|
||||
};
|
||||
|
||||
export const CartBlockContext = createContext< CartBlockContextProps >( {
|
||||
hasDarkControls: false,
|
||||
} );
|
||||
|
||||
export const useCartBlockContext = (): CartBlockContextProps => {
|
||||
return useContext( CartBlockContext );
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
/* tslint:disable */
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
useBlockProps,
|
||||
InnerBlocks,
|
||||
InspectorControls,
|
||||
} from '@wordpress/block-editor';
|
||||
import BlockErrorBoundary from '@woocommerce/base-components/block-error-boundary';
|
||||
import { EditorProvider, CartProvider } from '@woocommerce/base-context';
|
||||
import { previewCart } from '@woocommerce/resource-previews';
|
||||
import { SlotFillProvider } from '@woocommerce/blocks-checkout';
|
||||
import { useEffect, useRef } from '@wordpress/element';
|
||||
import { getQueryArg } from '@wordpress/url';
|
||||
import { dispatch, select } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './inner-blocks';
|
||||
import './editor.scss';
|
||||
import {
|
||||
addClassToBody,
|
||||
useBlockPropsWithLocking,
|
||||
BlockSettings,
|
||||
} from '../cart-checkout-shared';
|
||||
import '../cart-checkout-shared/sidebar-notices';
|
||||
import '../cart-checkout-shared/view-switcher';
|
||||
import { CartBlockContext } from './context';
|
||||
|
||||
// This is adds a class to body to signal if the selected block is locked
|
||||
addClassToBody();
|
||||
|
||||
// Array of allowed block names.
|
||||
const ALLOWED_BLOCKS = [
|
||||
'woocommerce/filled-cart-block',
|
||||
'woocommerce/empty-cart-block',
|
||||
];
|
||||
|
||||
export const Edit = ( { clientId, className, attributes, setAttributes } ) => {
|
||||
const { hasDarkControls, currentView, isPreview = false } = attributes;
|
||||
const defaultTemplate = [
|
||||
[ 'woocommerce/filled-cart-block', {}, [] ],
|
||||
[ 'woocommerce/empty-cart-block', {}, [] ],
|
||||
];
|
||||
const blockProps = useBlockPropsWithLocking( {
|
||||
className: classnames( className, 'wp-block-woocommerce-cart', {
|
||||
'is-editor-preview': isPreview,
|
||||
} ),
|
||||
} );
|
||||
|
||||
// This focuses on the block when a certain query param is found. This is used on the link from the task list.
|
||||
const focus = useRef( getQueryArg( window.location.href, 'focus' ) );
|
||||
|
||||
useEffect( () => {
|
||||
if (
|
||||
focus.current === 'cart' &&
|
||||
! select( 'core/block-editor' ).hasSelectedBlock()
|
||||
) {
|
||||
dispatch( 'core/block-editor' ).selectBlock( clientId );
|
||||
dispatch( 'core/interface' ).enableComplementaryArea(
|
||||
'core/edit-site',
|
||||
'edit-site/block-inspector'
|
||||
);
|
||||
}
|
||||
}, [ clientId ] );
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InspectorControls>
|
||||
<BlockSettings
|
||||
attributes={ attributes }
|
||||
setAttributes={ setAttributes }
|
||||
/>
|
||||
</InspectorControls>
|
||||
<BlockErrorBoundary
|
||||
header={ __(
|
||||
'Cart Block Error',
|
||||
'woocommerce'
|
||||
) }
|
||||
text={ __(
|
||||
'There was an error whilst rendering the cart block. If this problem continues, try re-creating the block.',
|
||||
'woocommerce'
|
||||
) }
|
||||
showErrorMessage={ true }
|
||||
errorMessagePrefix={ __(
|
||||
'Error message:',
|
||||
'woocommerce'
|
||||
) }
|
||||
>
|
||||
<EditorProvider
|
||||
previewData={ { previewCart } }
|
||||
currentView={ currentView }
|
||||
isPreview={ isPreview }
|
||||
>
|
||||
<CartBlockContext.Provider
|
||||
value={ {
|
||||
hasDarkControls,
|
||||
} }
|
||||
>
|
||||
<SlotFillProvider>
|
||||
<CartProvider>
|
||||
<InnerBlocks
|
||||
allowedBlocks={ ALLOWED_BLOCKS }
|
||||
template={ defaultTemplate }
|
||||
templateLock="insert"
|
||||
/>
|
||||
</CartProvider>
|
||||
</SlotFillProvider>
|
||||
</CartBlockContext.Provider>
|
||||
</EditorProvider>
|
||||
</BlockErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = () => {
|
||||
return (
|
||||
<div
|
||||
{ ...useBlockProps.save( {
|
||||
className: 'is-loading',
|
||||
} ) }
|
||||
>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
body.wc-lock-selected-block--move {
|
||||
.block-editor-block-mover__move-button-container,
|
||||
.block-editor-block-mover {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
body.wc-lock-selected-block--remove {
|
||||
.block-editor-block-settings-menu__popover {
|
||||
.components-menu-group:last-child {
|
||||
display: none;
|
||||
}
|
||||
.components-menu-group:nth-last-child(2) {
|
||||
margin-bottom: -12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-cart-items-block,
|
||||
.wp-block-woocommerce-cart-totals-block,
|
||||
.wp-block-woocommerce-empty-cart-block {
|
||||
// Temporary fix after the appender button was positioned absolute
|
||||
// See https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/5742#issuecomment-1032804168
|
||||
.block-list-appender {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-cart-order-summary-block {
|
||||
.block-editor-block-list__layout > div {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.wc-block-components-totals-wrapper {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { getValidBlockAttributes } from '@woocommerce/base-utils';
|
||||
import { Children, cloneElement, isValidElement } from '@wordpress/element';
|
||||
import { useStoreCart } from '@woocommerce/base-context';
|
||||
import { getRegisteredBlockComponents } from '@woocommerce/blocks-registry';
|
||||
|
||||
import { renderParentBlock } from '@woocommerce/atomic-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './inner-blocks/register-components';
|
||||
import Block from './block';
|
||||
import { blockName, blockAttributes } from './attributes';
|
||||
|
||||
const getProps = ( el ) => {
|
||||
return {
|
||||
attributes: getValidBlockAttributes(
|
||||
blockAttributes,
|
||||
!! el ? el.dataset : {}
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const Wrapper = ( { children } ) => {
|
||||
// we need to pluck out receiveCart.
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { extensions, receiveCart, ...cart } = useStoreCart();
|
||||
return Children.map( children, ( child ) => {
|
||||
if ( isValidElement( child ) ) {
|
||||
const componentProps = {
|
||||
extensions,
|
||||
cart,
|
||||
};
|
||||
return cloneElement( child, componentProps );
|
||||
}
|
||||
return child;
|
||||
} );
|
||||
};
|
||||
|
||||
renderParentBlock( {
|
||||
Block,
|
||||
blockName,
|
||||
selector: '.wp-block-woocommerce-cart',
|
||||
getProps,
|
||||
blockMap: getRegisteredBlockComponents( blockName ),
|
||||
blockWrapper: Wrapper,
|
||||
} );
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import classnames from 'classnames';
|
||||
import { InnerBlocks } from '@wordpress/block-editor';
|
||||
import { cart } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType, createBlock } from '@wordpress/blocks';
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import './style.scss';
|
||||
import { blockName, blockAttributes } from './attributes';
|
||||
import './inner-blocks';
|
||||
|
||||
/**
|
||||
* Register and run the Cart block.
|
||||
*/
|
||||
const settings = {
|
||||
title: __( 'Cart', 'woocommerce' ),
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ cart }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
category: 'woocommerce',
|
||||
keywords: [ __( 'WooCommerce', 'woocommerce' ) ],
|
||||
description: __( 'Shopping cart.', 'woocommerce' ),
|
||||
supports: {
|
||||
align: [ 'wide' ],
|
||||
html: false,
|
||||
multiple: false,
|
||||
},
|
||||
example: {
|
||||
attributes: {
|
||||
isPreview: true,
|
||||
},
|
||||
viewportWidth: 800,
|
||||
},
|
||||
attributes: blockAttributes,
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
transforms: {
|
||||
to: [
|
||||
{
|
||||
type: 'block',
|
||||
blocks: [ 'woocommerce/classic-shortcode' ],
|
||||
transform: ( attributes ) => {
|
||||
return createBlock(
|
||||
'woocommerce/classic-shortcode',
|
||||
{
|
||||
shortcode: 'cart',
|
||||
align: attributes.align,
|
||||
},
|
||||
[]
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// Migrates v1 to v2 checkout.
|
||||
deprecated: [
|
||||
{
|
||||
attributes: blockAttributes,
|
||||
save: ( { attributes } ) => {
|
||||
return (
|
||||
<div
|
||||
className={ classnames(
|
||||
'is-loading',
|
||||
attributes.className
|
||||
) }
|
||||
>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
migrate: ( attributes, innerBlocks ) => {
|
||||
const { checkoutPageId, align } = attributes;
|
||||
return [
|
||||
attributes,
|
||||
[
|
||||
createBlock(
|
||||
'woocommerce/filled-cart-block',
|
||||
{ align },
|
||||
[
|
||||
createBlock( 'woocommerce/cart-items-block' ),
|
||||
createBlock(
|
||||
'woocommerce/cart-totals-block',
|
||||
{},
|
||||
[
|
||||
createBlock(
|
||||
'woocommerce/cart-order-summary-block',
|
||||
{}
|
||||
),
|
||||
createBlock(
|
||||
'woocommerce/cart-express-payment-block'
|
||||
),
|
||||
createBlock(
|
||||
'woocommerce/proceed-to-checkout-block',
|
||||
{ checkoutPageId }
|
||||
),
|
||||
createBlock(
|
||||
'woocommerce/cart-accepted-payment-methods-block'
|
||||
),
|
||||
]
|
||||
),
|
||||
]
|
||||
),
|
||||
createBlock(
|
||||
'woocommerce/empty-cart-block',
|
||||
{ align },
|
||||
innerBlocks
|
||||
),
|
||||
],
|
||||
];
|
||||
},
|
||||
isEligible: ( _, innerBlocks ) => {
|
||||
return ! innerBlocks.find(
|
||||
( block ) => block.name === 'woocommerce/filled-cart-block'
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
registerBlockType( blockName, settings );
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "woocommerce/cart-accepted-payment-methods-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Accepted Payment Methods",
|
||||
"description": "Display accepted payment methods.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": true
|
||||
},
|
||||
"parent": [ "woocommerce/cart-totals-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { PaymentMethodIcons } from '@woocommerce/base-components/cart-checkout';
|
||||
import { usePaymentMethods } from '@woocommerce/base-context/hooks';
|
||||
import { getIconsFromPaymentMethods } from '@woocommerce/base-utils';
|
||||
|
||||
const Block = ( { className }: { className: string } ): JSX.Element => {
|
||||
const { paymentMethods } = usePaymentMethods();
|
||||
|
||||
return (
|
||||
<PaymentMethodIcons
|
||||
className={ className }
|
||||
icons={ getIconsFromPaymentMethods( paymentMethods ) }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: { className: string };
|
||||
} ): JSX.Element => {
|
||||
const { className } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Block className={ className } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
import { Icon, payment } from '@wordpress/icons';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-accepted-payment-methods-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ payment }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "woocommerce/cart-cross-sells-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Cart Cross-Sells",
|
||||
"description": "Shows the Cross-Sells block.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": true
|
||||
},
|
||||
"parent": [ "woocommerce/cart-items-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import type { TemplateArray } from '@wordpress/blocks';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||
|
||||
export const Edit = (): JSX.Element => {
|
||||
const blockProps = useBlockProps( {
|
||||
className: 'wc-block-cart__cross-sells',
|
||||
} );
|
||||
const defaultTemplate = [
|
||||
[
|
||||
'core/heading',
|
||||
{
|
||||
content: __(
|
||||
'You may be interested in…',
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
level: 2,
|
||||
fontSize: 'large',
|
||||
},
|
||||
[],
|
||||
],
|
||||
[ 'woocommerce/cart-cross-sells-products-block', {}, [] ],
|
||||
] as TemplateArray;
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InnerBlocks template={ defaultTemplate } templateLock={ false } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return (
|
||||
<div { ...useBlockProps.save() }>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
interface Props {
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const FrontendBlock = ( {
|
||||
children,
|
||||
className = '',
|
||||
}: Props ): JSX.Element | null => {
|
||||
const { crossSellsProducts, cartIsLoading } = useStoreCart();
|
||||
|
||||
if ( cartIsLoading || crossSellsProducts.length < 1 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <div className={ className }>{ children }</div>;
|
||||
};
|
||||
|
||||
export default FrontendBlock;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, column } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-cross-sells-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ column }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "woocommerce/cart-cross-sells-products-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Cart Cross-Sells Products",
|
||||
"description": "Shows the Cross-Sells products.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"columns": {
|
||||
"type": "number",
|
||||
"default": 3
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-cross-sells-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import CartCrossSellsProductList from '../../cart-cross-sells-product-list';
|
||||
import metadata from './block.json';
|
||||
|
||||
interface BlockProps {
|
||||
className?: string | undefined;
|
||||
columns: number;
|
||||
}
|
||||
|
||||
const Block = ( { className, columns }: BlockProps ): JSX.Element => {
|
||||
const { crossSellsProducts } = useStoreCart();
|
||||
|
||||
if ( typeof columns === 'undefined' ) {
|
||||
columns = metadata.attributes.columns.default;
|
||||
}
|
||||
|
||||
return (
|
||||
<CartCrossSellsProductList
|
||||
className={ className }
|
||||
columns={ columns }
|
||||
products={ crossSellsProducts }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { PanelBody, RangeControl } from '@wordpress/components';
|
||||
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
import Noninteractive from '@woocommerce/base-components/noninteractive';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
import './editor.scss';
|
||||
|
||||
interface Attributes {
|
||||
className?: string;
|
||||
columns: number;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
attributes: Attributes;
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
}
|
||||
|
||||
export const Edit = ( { attributes, setAttributes }: Props ): JSX.Element => {
|
||||
const { className, columns } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InspectorControls>
|
||||
<PanelBody
|
||||
title={ __( 'Settings', 'woo-gutenberg-products-block' ) }
|
||||
>
|
||||
<RangeControl
|
||||
label={ __(
|
||||
'Cross-Sells products to show',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
value={ columns }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { columns: value } )
|
||||
}
|
||||
min={ getSetting( 'minColumns', 1 ) }
|
||||
max={ getSetting( 'maxColumns', 6 ) }
|
||||
/>
|
||||
</PanelBody>
|
||||
</InspectorControls>
|
||||
<Noninteractive>
|
||||
<Block columns={ columns } className={ className } />
|
||||
</Noninteractive>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
.wp-block-woocommerce-cart-cross-sells-products-block {
|
||||
|
||||
.cross-sells-product {
|
||||
display: inline-block;
|
||||
margin-bottom: 2em;
|
||||
padding-right: 5%;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
width: 30%;
|
||||
|
||||
&:nth-child(3n + 3) {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
.wc-block-components-product-name {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.wc-block-components-product-price {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-components-product-add-to-cart-button:not(.is-link) {
|
||||
background-color: #eee;
|
||||
color: #333;
|
||||
margin-top: 1em;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
background-color: #d5d5d5;
|
||||
border-color: #d5d5d5;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, column } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import './style.scss';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-cross-sells-products-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ column }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,72 @@
|
||||
.wp-block-woocommerce-cart {
|
||||
|
||||
&.is-loading .wp-block-woocommerce-cart-cross-sells-block {
|
||||
@include placeholder();
|
||||
margin-top: 2em;
|
||||
min-height: 15em;
|
||||
|
||||
h3 {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-cart-cross-sells-block {
|
||||
|
||||
.cross-sells-product {
|
||||
display: inline-block;
|
||||
box-sizing: content-box;
|
||||
margin-bottom: 2em;
|
||||
padding-right: 5%;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
width: 30%;
|
||||
|
||||
&:nth-child(3n + 3) {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
div {
|
||||
.wc-block-components-product-name {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.wc-block-components-product-price {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.wc-block-components-product-button__button {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.wc-block-components-product-add-to-cart {
|
||||
justify-content: center;
|
||||
|
||||
.wc-block-components-product-add-to-cart-button:not(.is-link) {
|
||||
background-color: #eee;
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
margin-top: 1em;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
background-color: #d5d5d5;
|
||||
border-color: #d5d5d5;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include breakpoint("<480px") {
|
||||
.wp-block-woocommerce-cart {
|
||||
.wp-block-woocommerce-cart-cross-sells-block {
|
||||
.cross-sells-product {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "woocommerce/cart-express-payment-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Express Checkout",
|
||||
"description": "Allow customers to breeze through with quick payment options.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-totals-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { CartExpressPayment } from '../../../cart-checkout-shared/payment-methods';
|
||||
|
||||
const Block = ( { className }: { className: string } ): JSX.Element | null => {
|
||||
const { cartNeedsPayment } = useStoreCart();
|
||||
|
||||
if ( ! cartNeedsPayment ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={ classnames(
|
||||
'wc-block-cart__payment-options',
|
||||
className
|
||||
) }
|
||||
>
|
||||
<CartExpressPayment />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
import { useExpressPaymentMethods } from '@woocommerce/base-context/hooks';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
import './editor.scss';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: { className: string };
|
||||
} ): JSX.Element | null => {
|
||||
const { paymentMethods, isInitialized } = useExpressPaymentMethods();
|
||||
const hasExpressPaymentMethods = Object.keys( paymentMethods ).length > 0;
|
||||
const blockProps = useBlockProps( {
|
||||
className: classnames( {
|
||||
'wp-block-woocommerce-cart-express-payment-block--has-express-payment-methods':
|
||||
hasExpressPaymentMethods,
|
||||
} ),
|
||||
} );
|
||||
const { className } = attributes;
|
||||
|
||||
if ( ! isInitialized || ! hasExpressPaymentMethods ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Block className={ className } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
// Adjust padding and margins in the editor to improve selected block outlines.
|
||||
.wp-block-woocommerce-cart-express-payment-block {
|
||||
.components-placeholder__label svg {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.wc-block-cart__payment-options {
|
||||
padding: 0;
|
||||
|
||||
.wc-block-components-express-payment-continue-rule {
|
||||
margin-bottom: -12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-proceed-to-checkout-block {
|
||||
margin-bottom: 28px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-checkout-express-payment-block-placeholder {
|
||||
* {
|
||||
pointer-events: all; // Overrides parent disabled component in editor context
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-cart-express-payment-block &,
|
||||
.wp-block-woocommerce-checkout-express-payment-block-placeholder__description {
|
||||
margin: 0 0 1em;
|
||||
}
|
||||
|
||||
.wp-block-woocommerce-checkout-express-payment-block-placeholder__description {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import expressIcon from '../../../cart-checkout-shared/icon';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-express-payment-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
style={ { fill: 'none' } } // this is needed for this particular svg
|
||||
icon={ expressIcon }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "woocommerce/cart-items-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Cart Items",
|
||||
"description": "Column containing cart items.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/filled-cart-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||
import { Main } from '@woocommerce/base-components/sidebar-layout';
|
||||
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
|
||||
import type { TemplateArray } from '@wordpress/blocks';
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
useForcedLayout,
|
||||
getAllowedBlocks,
|
||||
} from '../../../cart-checkout-shared';
|
||||
|
||||
interface Props {
|
||||
clientId: string;
|
||||
}
|
||||
|
||||
export const Edit = ( { clientId }: Props ): JSX.Element => {
|
||||
const blockProps = useBlockProps( { className: 'wc-block-cart__main' } );
|
||||
const allowedBlocks = getAllowedBlocks( innerBlockAreas.CART_ITEMS );
|
||||
const defaultTemplate = [
|
||||
[ 'woocommerce/cart-line-items-block', {}, [] ],
|
||||
[ 'woocommerce/cart-cross-sells-block', {}, [] ],
|
||||
] as unknown as TemplateArray;
|
||||
|
||||
useForcedLayout( {
|
||||
clientId,
|
||||
registeredBlocks: allowedBlocks,
|
||||
defaultTemplate,
|
||||
} );
|
||||
return (
|
||||
<Main { ...blockProps }>
|
||||
<InnerBlocks
|
||||
allowedBlocks={ allowedBlocks }
|
||||
template={ defaultTemplate }
|
||||
templateLock={ false }
|
||||
renderAppender={ InnerBlocks.ButtonBlockAppender }
|
||||
/>
|
||||
</Main>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return (
|
||||
<div { ...useBlockProps.save() }>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Main } from '@woocommerce/base-components/sidebar-layout';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const FrontendBlock = ( {
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: JSX.Element;
|
||||
className: string;
|
||||
} ): JSX.Element => {
|
||||
return (
|
||||
<Main className={ classnames( 'wc-block-cart__main', className ) }>
|
||||
{ children }
|
||||
</Main>
|
||||
);
|
||||
};
|
||||
|
||||
export default FrontendBlock;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, column } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-items-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ column }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "woocommerce/cart-line-items-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Cart Line Items",
|
||||
"description": "Block containing current line items in Cart.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-items-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
import { CartLineItemsTable } from '@woocommerce/base-components/cart-checkout';
|
||||
|
||||
const Block = ( { className }: { className: string } ): JSX.Element => {
|
||||
const { cartItems, cartIsLoading } = useStoreCart();
|
||||
return (
|
||||
<CartLineItemsTable
|
||||
className={ className }
|
||||
lineItems={ cartItems }
|
||||
isLoading={ cartIsLoading }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
import Noninteractive from '@woocommerce/base-components/noninteractive';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: { className: string };
|
||||
} ): JSX.Element => {
|
||||
const { className } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Noninteractive>
|
||||
<Block className={ className } />
|
||||
</Noninteractive>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, column } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-line-items-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ column }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Order Summary",
|
||||
"description": "Show customers a summary of their order.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-totals-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||
import type { TemplateArray } from '@wordpress/blocks';
|
||||
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { TotalsFooterItem } from '@woocommerce/base-components/cart-checkout';
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
useForcedLayout,
|
||||
getAllowedBlocks,
|
||||
} from '../../../cart-checkout-shared';
|
||||
import { OrderMetaSlotFill } from './slotfills';
|
||||
|
||||
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
|
||||
const blockProps = useBlockProps();
|
||||
const { cartTotals } = useStoreCart();
|
||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||
const allowedBlocks = getAllowedBlocks(
|
||||
innerBlockAreas.CART_ORDER_SUMMARY
|
||||
);
|
||||
const defaultTemplate = [
|
||||
[
|
||||
'woocommerce/cart-order-summary-heading-block',
|
||||
{
|
||||
content: __( 'Cart totals', 'woo-gutenberg-products-block' ),
|
||||
},
|
||||
[],
|
||||
],
|
||||
[ 'woocommerce/cart-order-summary-coupon-form-block', {}, [] ],
|
||||
[ 'woocommerce/cart-order-summary-subtotal-block', {}, [] ],
|
||||
[ 'woocommerce/cart-order-summary-fee-block', {}, [] ],
|
||||
[ 'woocommerce/cart-order-summary-discount-block', {}, [] ],
|
||||
[ 'woocommerce/cart-order-summary-shipping-block', {}, [] ],
|
||||
[ 'woocommerce/cart-order-summary-taxes-block', {}, [] ],
|
||||
] as TemplateArray;
|
||||
|
||||
useForcedLayout( {
|
||||
clientId,
|
||||
registeredBlocks: allowedBlocks,
|
||||
defaultTemplate,
|
||||
} );
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InnerBlocks
|
||||
allowedBlocks={ allowedBlocks }
|
||||
template={ defaultTemplate }
|
||||
/>
|
||||
<div className="wc-block-components-totals-wrapper">
|
||||
<TotalsFooterItem
|
||||
currency={ totalsCurrency }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
</div>
|
||||
{ /* do I put an totals wrapper here? */ }
|
||||
<OrderMetaSlotFill />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return (
|
||||
<div { ...useBlockProps.save() }>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { TotalsFooterItem } from '@woocommerce/base-components/cart-checkout';
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { OrderMetaSlotFill } from './slotfills';
|
||||
|
||||
const FrontendBlock = ( {
|
||||
children,
|
||||
className = '',
|
||||
}: {
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
className?: string;
|
||||
} ): JSX.Element | null => {
|
||||
const { cartTotals } = useStoreCart();
|
||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||
|
||||
return (
|
||||
<div className={ className }>
|
||||
{ children }
|
||||
<div className="wc-block-components-totals-wrapper">
|
||||
<TotalsFooterItem
|
||||
currency={ totalsCurrency }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
</div>
|
||||
<OrderMetaSlotFill />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FrontendBlock;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { totals } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ totals }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { ExperimentalOrderMeta } from '@woocommerce/blocks-checkout';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
export const OrderMetaSlotFill = (): JSX.Element => {
|
||||
// Prepare props to pass to the ExperimentalOrderMeta slot fill. We need to pluck out receiveCart.
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { extensions, receiveCart, ...cart } = useStoreCart();
|
||||
const slotFillProps = {
|
||||
extensions,
|
||||
cart,
|
||||
context: 'woocommerce/cart',
|
||||
};
|
||||
|
||||
return <ExperimentalOrderMeta.Slot { ...slotFillProps } />;
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-coupon-form-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Coupon Form",
|
||||
"description": "Shows the apply coupon form.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false
|
||||
},
|
||||
"attributes": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": false,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-order-summary-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { TotalsCoupon } from '@woocommerce/base-components/cart-checkout';
|
||||
import { useStoreCartCoupons } from '@woocommerce/base-context/hooks';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
import { TotalsWrapper } from '@woocommerce/blocks-components';
|
||||
|
||||
const Block = ( { className }: { className: string } ): JSX.Element | null => {
|
||||
const couponsEnabled = getSetting( 'couponsEnabled', true );
|
||||
|
||||
const { applyCoupon, isApplyingCoupon } = useStoreCartCoupons( 'wc/cart' );
|
||||
|
||||
if ( ! couponsEnabled ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<TotalsWrapper className={ className }>
|
||||
<TotalsCoupon
|
||||
onSubmit={ applyCoupon }
|
||||
isLoading={ isApplyingCoupon }
|
||||
/>
|
||||
</TotalsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
import Noninteractive from '@woocommerce/base-components/noninteractive';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: {
|
||||
className: string;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
} ): JSX.Element => {
|
||||
const { className } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Noninteractive>
|
||||
<Block className={ className } />
|
||||
</Noninteractive>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, tag } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-coupon-form-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ tag }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-discount-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Discount",
|
||||
"description": "Shows the cart discount row.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-order-summary-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { TotalsDiscount } from '@woocommerce/base-components/cart-checkout';
|
||||
import { TotalsWrapper } from '@woocommerce/blocks-components';
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import {
|
||||
useStoreCartCoupons,
|
||||
useStoreCart,
|
||||
} from '@woocommerce/base-context/hooks';
|
||||
import { ExperimentalDiscountsMeta } from '@woocommerce/blocks-checkout';
|
||||
|
||||
const DiscountSlotFill = (): JSX.Element => {
|
||||
// Prepare props to pass to the ExperimentalOrderMeta slot fill. We need to pluck out receiveCart.
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { extensions, receiveCart, ...cart } = useStoreCart();
|
||||
const discountsSlotFillProps = {
|
||||
extensions,
|
||||
cart,
|
||||
context: 'woocommerce/cart',
|
||||
};
|
||||
|
||||
return <ExperimentalDiscountsMeta.Slot { ...discountsSlotFillProps } />;
|
||||
};
|
||||
|
||||
const Block = ( { className }: { className: string } ): JSX.Element => {
|
||||
const { cartTotals, cartCoupons } = useStoreCart();
|
||||
const { removeCoupon, isRemovingCoupon } = useStoreCartCoupons( 'wc/cart' );
|
||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||
|
||||
return (
|
||||
<>
|
||||
<TotalsWrapper className={ className }>
|
||||
<TotalsDiscount
|
||||
cartCoupons={ cartCoupons }
|
||||
currency={ totalsCurrency }
|
||||
isRemovingCoupon={ isRemovingCoupon }
|
||||
removeCoupon={ removeCoupon }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
</TotalsWrapper>
|
||||
<DiscountSlotFill />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: {
|
||||
className: string;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
} ): JSX.Element => {
|
||||
const { className } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Block className={ className } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { totals } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-discount-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ totals }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-fee-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Fees",
|
||||
"description": "Shows the cart fee row.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-order-summary-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { TotalsFees, TotalsWrapper } from '@woocommerce/blocks-components';
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
const Block = ( { className }: { className: string } ): JSX.Element => {
|
||||
const { cartFees, cartTotals } = useStoreCart();
|
||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||
|
||||
return (
|
||||
<TotalsWrapper className={ className }>
|
||||
<TotalsFees currency={ totalsCurrency } cartFees={ cartFees } />
|
||||
</TotalsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: {
|
||||
className: string;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
} ): JSX.Element => {
|
||||
const { className } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Block className={ className } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { totals } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-fee-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ totals }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
export default {
|
||||
content: {
|
||||
type: 'string',
|
||||
default: __( 'Cart totals', 'woo-gutenberg-products-block' ),
|
||||
},
|
||||
lock: {
|
||||
type: 'object',
|
||||
default: {
|
||||
remove: false,
|
||||
move: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-heading-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Heading",
|
||||
"description": "Shows the heading row.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false
|
||||
},
|
||||
"attributes": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"default": "Cart totals"
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": false,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-order-summary-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
|
||||
const Block = ( {
|
||||
className,
|
||||
content = '',
|
||||
}: {
|
||||
className: string;
|
||||
content: string;
|
||||
} ): JSX.Element => {
|
||||
return (
|
||||
<span
|
||||
className={ classnames( className, 'wc-block-cart__totals-title' ) }
|
||||
>
|
||||
{ content }
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { PlainText, useBlockProps } from '@wordpress/block-editor';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './editor.scss';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
setAttributes,
|
||||
}: {
|
||||
attributes: {
|
||||
content: string;
|
||||
className: string;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
} ): JSX.Element => {
|
||||
const { content = '', className = '' } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<span
|
||||
className={ classnames(
|
||||
className,
|
||||
'wc-block-cart__totals-title'
|
||||
) }
|
||||
>
|
||||
<PlainText
|
||||
className={ '' }
|
||||
value={ content }
|
||||
onChange={ ( value ) =>
|
||||
setAttributes( { content: value } )
|
||||
}
|
||||
style={ { backgroundColor: 'transparent' } }
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
.wp-block-woocommerce-cart-order-summary-heading-block {
|
||||
textarea {
|
||||
text-align: right;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { withFilteredAttributes } from '@woocommerce/shared-hocs';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
import attributes from './attributes';
|
||||
|
||||
export default withFilteredAttributes( attributes )( Block );
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { totals } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-heading-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ totals }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-shipping-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Shipping",
|
||||
"description": "Shows the cart shipping row.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-order-summary-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { TotalsShipping } from '@woocommerce/base-components/cart-checkout';
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
import { TotalsWrapper } from '@woocommerce/blocks-components';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
|
||||
const Block = ( { className }: { className: string } ): JSX.Element | null => {
|
||||
const { cartTotals, cartNeedsShipping } = useStoreCart();
|
||||
|
||||
if ( ! cartNeedsShipping ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||
|
||||
return (
|
||||
<TotalsWrapper className={ className }>
|
||||
<TotalsShipping
|
||||
showCalculator={ getSetting< boolean >(
|
||||
'isShippingCalculatorEnabled',
|
||||
true
|
||||
) }
|
||||
showRateSelector={ true }
|
||||
values={ cartTotals }
|
||||
currency={ totalsCurrency }
|
||||
/>
|
||||
</TotalsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
|
||||
import { PanelBody, ExternalLink } from '@wordpress/components';
|
||||
import { ADMIN_URL, getSetting } from '@woocommerce/settings';
|
||||
import Noninteractive from '@woocommerce/base-components/noninteractive';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: {
|
||||
className: string;
|
||||
lock: {
|
||||
move: boolean;
|
||||
remove: boolean;
|
||||
};
|
||||
};
|
||||
} ): JSX.Element => {
|
||||
const { className } = attributes;
|
||||
const shippingEnabled = getSetting( 'shippingEnabled', true );
|
||||
const blockProps = useBlockProps();
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InspectorControls>
|
||||
{ !! shippingEnabled && (
|
||||
<PanelBody
|
||||
title={ __(
|
||||
'Shipping Calculations',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
>
|
||||
<p className="wc-block-checkout__controls-text">
|
||||
{ __(
|
||||
'Options that control shipping can be managed in your store settings.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
</p>
|
||||
<ExternalLink
|
||||
href={ `${ ADMIN_URL }admin.php?page=wc-settings&tab=shipping§ion=options` }
|
||||
>
|
||||
{ __(
|
||||
'Manage shipping options',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
</ExternalLink>{ ' ' }
|
||||
</PanelBody>
|
||||
) }
|
||||
</InspectorControls>
|
||||
<Noninteractive>
|
||||
<Block className={ className } />
|
||||
</Noninteractive>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { totals } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-shipping-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ totals }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-subtotal-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Subtotal",
|
||||
"description": "Shows the cart subtotal row.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-order-summary-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Subtotal, TotalsWrapper } from '@woocommerce/blocks-components';
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
const Block = ( { className = '' }: { className?: string } ): JSX.Element => {
|
||||
const { cartTotals } = useStoreCart();
|
||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||
|
||||
return (
|
||||
<TotalsWrapper className={ className }>
|
||||
<Subtotal currency={ totalsCurrency } values={ cartTotals } />
|
||||
</TotalsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
}: {
|
||||
attributes: {
|
||||
className: string;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
} ): JSX.Element => {
|
||||
const { className } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<Block className={ className } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { totals } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-subtotal-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ totals }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
|
||||
export default {
|
||||
showRateAfterTaxName: {
|
||||
type: 'boolean',
|
||||
default: getSetting( 'displayCartPricesIncludingTax', false ),
|
||||
},
|
||||
lock: {
|
||||
type: 'object',
|
||||
default: {
|
||||
remove: true,
|
||||
move: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "woocommerce/cart-order-summary-taxes-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Taxes",
|
||||
"description": "Shows the cart taxes row.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"className": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart-order-summary-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { TotalsTaxes, TotalsWrapper } from '@woocommerce/blocks-components';
|
||||
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
|
||||
const Block = ( {
|
||||
className,
|
||||
showRateAfterTaxName,
|
||||
}: {
|
||||
className: string;
|
||||
showRateAfterTaxName: boolean;
|
||||
} ): JSX.Element | null => {
|
||||
const { cartTotals } = useStoreCart();
|
||||
|
||||
const displayCartPricesIncludingTax = getSetting(
|
||||
'displayCartPricesIncludingTax',
|
||||
false
|
||||
);
|
||||
|
||||
if (
|
||||
displayCartPricesIncludingTax ||
|
||||
parseInt( cartTotals.total_tax, 10 ) <= 0
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const totalsCurrency = getCurrencyFromPriceResponse( cartTotals );
|
||||
|
||||
return (
|
||||
<TotalsWrapper className={ className }>
|
||||
<TotalsTaxes
|
||||
showRateAfterTaxName={ showRateAfterTaxName }
|
||||
currency={ totalsCurrency }
|
||||
values={ cartTotals }
|
||||
/>
|
||||
</TotalsWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default Block;
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
|
||||
import { PanelBody, ToggleControl } from '@wordpress/components';
|
||||
import { getSetting } from '@woocommerce/settings';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
|
||||
export const Edit = ( {
|
||||
attributes,
|
||||
setAttributes,
|
||||
}: {
|
||||
attributes: {
|
||||
className: string;
|
||||
showRateAfterTaxName: boolean;
|
||||
};
|
||||
setAttributes: ( attributes: Record< string, unknown > ) => void;
|
||||
} ): JSX.Element => {
|
||||
const { className, showRateAfterTaxName } = attributes;
|
||||
const blockProps = useBlockProps();
|
||||
const taxesEnabled = getSetting( 'taxesEnabled' ) as boolean;
|
||||
const displayItemizedTaxes = getSetting(
|
||||
'displayItemizedTaxes',
|
||||
false
|
||||
) as boolean;
|
||||
const displayCartPricesIncludingTax = getSetting(
|
||||
'displayCartPricesIncludingTax',
|
||||
false
|
||||
) as boolean;
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<InspectorControls>
|
||||
{ taxesEnabled &&
|
||||
displayItemizedTaxes &&
|
||||
! displayCartPricesIncludingTax && (
|
||||
<PanelBody
|
||||
title={ __(
|
||||
'Taxes',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
>
|
||||
<ToggleControl
|
||||
label={ __(
|
||||
'Show rate after tax name',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
help={ __(
|
||||
'Show the percentage rate alongside each tax line in the summary.',
|
||||
'woo-gutenberg-products-block'
|
||||
) }
|
||||
checked={ showRateAfterTaxName }
|
||||
onChange={ () =>
|
||||
setAttributes( {
|
||||
showRateAfterTaxName:
|
||||
! showRateAfterTaxName,
|
||||
} )
|
||||
}
|
||||
/>
|
||||
</PanelBody>
|
||||
) }
|
||||
</InspectorControls>
|
||||
<Block
|
||||
className={ className }
|
||||
showRateAfterTaxName={ showRateAfterTaxName }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return <div { ...useBlockProps.save() } />;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { withFilteredAttributes } from '@woocommerce/shared-hocs';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import Block from './block';
|
||||
import attributes from './attributes';
|
||||
|
||||
export default withFilteredAttributes( attributes )( Block );
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { totals } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import attributes from './attributes';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-order-summary-taxes-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ totals }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
attributes,
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "woocommerce/cart-totals-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Cart Totals",
|
||||
"description": "Column containing the cart totals.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"checkbox": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"required": false
|
||||
},
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/filled-cart-block" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||
import { Sidebar } from '@woocommerce/base-components/sidebar-layout';
|
||||
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
|
||||
import type { TemplateArray } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
useForcedLayout,
|
||||
getAllowedBlocks,
|
||||
} from '../../../cart-checkout-shared';
|
||||
|
||||
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
|
||||
const blockProps = useBlockProps( { className: 'wc-block-cart__sidebar' } );
|
||||
const allowedBlocks = getAllowedBlocks( innerBlockAreas.CART_TOTALS );
|
||||
const defaultTemplate = [
|
||||
[ 'woocommerce/cart-order-summary-block', {}, [] ],
|
||||
[ 'woocommerce/cart-express-payment-block', {}, [] ],
|
||||
[ 'woocommerce/proceed-to-checkout-block', {}, [] ],
|
||||
[ 'woocommerce/cart-accepted-payment-methods-block', {}, [] ],
|
||||
] as TemplateArray;
|
||||
|
||||
useForcedLayout( {
|
||||
clientId,
|
||||
registeredBlocks: allowedBlocks,
|
||||
defaultTemplate,
|
||||
} );
|
||||
|
||||
return (
|
||||
<Sidebar { ...blockProps }>
|
||||
<InnerBlocks
|
||||
allowedBlocks={ allowedBlocks }
|
||||
template={ defaultTemplate }
|
||||
templateLock={ false }
|
||||
renderAppender={ InnerBlocks.ButtonBlockAppender }
|
||||
/>
|
||||
</Sidebar>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return (
|
||||
<div { ...useBlockProps.save() }>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
import { Sidebar } from '@woocommerce/base-components/sidebar-layout';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
const FrontendBlock = ( {
|
||||
children,
|
||||
className = '',
|
||||
}: {
|
||||
children: JSX.Element | JSX.Element[];
|
||||
className?: string;
|
||||
} ): JSX.Element => {
|
||||
return (
|
||||
<Sidebar
|
||||
className={ classnames( 'wc-block-cart__sidebar', className ) }
|
||||
>
|
||||
{ children }
|
||||
</Sidebar>
|
||||
);
|
||||
};
|
||||
|
||||
export default FrontendBlock;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Icon, column } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import './style.scss';
|
||||
|
||||
registerBlockType( 'woocommerce/cart-totals-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ column }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,8 @@
|
||||
.is-mobile,
|
||||
.is-small,
|
||||
.is-medium {
|
||||
.wc-block-cart__sidebar {
|
||||
margin-bottom: $gap-large;
|
||||
order: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import FILLED_CART from './filled-cart-block/block.json';
|
||||
import EMPTY_CART from './empty-cart-block/block.json';
|
||||
import CART_ITEMS from './cart-items-block/block.json';
|
||||
import CART_EXPRESS_PAYMENT from './cart-express-payment-block/block.json';
|
||||
import CART_LINE_ITEMS from './cart-line-items-block/block.json';
|
||||
import CART_CROSS_SELLS from './cart-cross-sells-block/block.json';
|
||||
import CART_CROSS_SELLS_PRODUCTS from './cart-cross-sells-products/block.json';
|
||||
import CART_TOTALS from './cart-totals-block/block.json';
|
||||
import PROCEED_TO_CHECKOUT from './proceed-to-checkout-block/block.json';
|
||||
import CART_ACCEPTED_PAYMENT_METHODS from './cart-accepted-payment-methods-block/block.json';
|
||||
import CART_ORDER_SUMMARY from './cart-order-summary-block/block.json';
|
||||
import CART_ORDER_SUMMARY_SUBTOTAL from './cart-order-summary-subtotal/block.json';
|
||||
import CART_ORDER_SUMMARY_FEE from './cart-order-summary-fee/block.json';
|
||||
import CART_ORDER_SUMMARY_DISCOUNT from './cart-order-summary-discount/block.json';
|
||||
import CART_ORDER_SUMMARY_SHIPPING from './cart-order-summary-shipping/block.json';
|
||||
import CART_ORDER_SUMMARY_COUPON_FORM from './cart-order-summary-coupon-form/block.json';
|
||||
import CART_ORDER_SUMMARY_TAXES from './cart-order-summary-taxes/block.json';
|
||||
import CART_ORDER_SUMMARY_HEADING from './cart-order-summary-heading/block.json';
|
||||
|
||||
export default {
|
||||
FILLED_CART,
|
||||
EMPTY_CART,
|
||||
CART_ITEMS,
|
||||
CART_EXPRESS_PAYMENT,
|
||||
CART_LINE_ITEMS,
|
||||
CART_CROSS_SELLS,
|
||||
CART_CROSS_SELLS_PRODUCTS,
|
||||
CART_TOTALS,
|
||||
PROCEED_TO_CHECKOUT,
|
||||
CART_ACCEPTED_PAYMENT_METHODS,
|
||||
CART_ORDER_SUMMARY,
|
||||
CART_ORDER_SUMMARY_SUBTOTAL,
|
||||
CART_ORDER_SUMMARY_FEE,
|
||||
CART_ORDER_SUMMARY_DISCOUNT,
|
||||
CART_ORDER_SUMMARY_SHIPPING,
|
||||
CART_ORDER_SUMMARY_COUPON_FORM,
|
||||
CART_ORDER_SUMMARY_TAXES,
|
||||
CART_ORDER_SUMMARY_HEADING,
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "woocommerce/empty-cart-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Empty Cart",
|
||||
"description": "Contains blocks that are displayed when the cart is empty.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": [ "wide" ],
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
|
||||
import type { TemplateArray } from '@wordpress/blocks';
|
||||
import { useEditorContext } from '@woocommerce/base-context';
|
||||
import { SHOP_URL } from '@woocommerce/block-settings';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
useForcedLayout,
|
||||
getAllowedBlocks,
|
||||
} from '../../../cart-checkout-shared';
|
||||
|
||||
const browseStoreTemplate = SHOP_URL
|
||||
? [
|
||||
'core/paragraph',
|
||||
{
|
||||
align: 'center',
|
||||
content: sprintf(
|
||||
/* translators: %s is the link to the store product directory. */
|
||||
__(
|
||||
'<a href="%s">Browse store</a>',
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
SHOP_URL
|
||||
),
|
||||
dropCap: false,
|
||||
},
|
||||
]
|
||||
: null;
|
||||
|
||||
const defaultTemplate = [
|
||||
[
|
||||
'core/heading',
|
||||
{
|
||||
textAlign: 'center',
|
||||
content: __(
|
||||
'Your cart is currently empty!',
|
||||
'woo-gutenberg-products-block'
|
||||
),
|
||||
level: 2,
|
||||
className: 'with-empty-cart-icon wc-block-cart__empty-cart__title',
|
||||
},
|
||||
],
|
||||
browseStoreTemplate,
|
||||
[
|
||||
'core/separator',
|
||||
{
|
||||
className: 'is-style-dots',
|
||||
},
|
||||
],
|
||||
[
|
||||
'core/heading',
|
||||
{
|
||||
textAlign: 'center',
|
||||
content: __( 'New in store', 'woo-gutenberg-products-block' ),
|
||||
level: 2,
|
||||
},
|
||||
],
|
||||
[
|
||||
'woocommerce/product-new',
|
||||
{
|
||||
columns: 4,
|
||||
rows: 1,
|
||||
},
|
||||
],
|
||||
].filter( Boolean ) as unknown as TemplateArray;
|
||||
|
||||
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
|
||||
const blockProps = useBlockProps();
|
||||
const { currentView } = useEditorContext();
|
||||
const allowedBlocks = getAllowedBlocks( innerBlockAreas.EMPTY_CART );
|
||||
|
||||
useForcedLayout( {
|
||||
clientId,
|
||||
registeredBlocks: allowedBlocks,
|
||||
defaultTemplate,
|
||||
} );
|
||||
|
||||
return (
|
||||
<div
|
||||
{ ...blockProps }
|
||||
hidden={ currentView !== 'woocommerce/empty-cart-block' }
|
||||
>
|
||||
<InnerBlocks
|
||||
template={ defaultTemplate }
|
||||
templateLock={ false }
|
||||
renderAppender={ InnerBlocks.ButtonBlockAppender }
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return (
|
||||
<div { ...useBlockProps.save() }>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
import { useEffect } from '@wordpress/element';
|
||||
import { dispatchEvent } from '@woocommerce/base-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
const FrontendBlock = ( {
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: JSX.Element;
|
||||
className: string;
|
||||
} ): JSX.Element | null => {
|
||||
const { cartItems, cartIsLoading } = useStoreCart();
|
||||
useEffect( () => {
|
||||
if ( cartItems.length !== 0 || cartIsLoading ) {
|
||||
return;
|
||||
}
|
||||
dispatchEvent( 'wc-blocks_render_blocks_frontend', {
|
||||
element: document.body.querySelector(
|
||||
'.wp-block-woocommerce-cart'
|
||||
),
|
||||
} );
|
||||
}, [ cartIsLoading, cartItems ] );
|
||||
if ( ! cartIsLoading && cartItems.length === 0 ) {
|
||||
return <div className={ className }>{ children }</div>;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default FrontendBlock;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { removeCart } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
import './style.scss';
|
||||
|
||||
registerBlockType( 'woocommerce/empty-cart-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ removeCart }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,22 @@
|
||||
.wc-block-cart__empty-cart__title,
|
||||
.editor-styles-wrapper .wc-block-cart__empty-cart__title {
|
||||
font-size: inherit;
|
||||
}
|
||||
.wc-block-cart__empty-cart__title.with-empty-cart-icon {
|
||||
&::before {
|
||||
content: "";
|
||||
background-color: currentColor;
|
||||
display: block;
|
||||
margin: 0 auto 2em;
|
||||
mask-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOCIgaGVpZ2h0PSIzOCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iY3VycmVudENvbG9yIiBkPSJNMTkgMEM4LjUwNCAwIDAgOC41MDQgMCAxOXM4LjUwNCAxOSAxOSAxOSAxOS04LjUwNCAxOS0xOVMyOS40OTYgMCAxOSAwWm02LjEyOSAxMi44NzFhMi40NDkgMi40NDkgMCAwIDEgMi40NTIgMi40NTIgMi40NDkgMi40NDkgMCAwIDEtMi40NTIgMi40NTEgMi40NDkgMi40NDkgMCAwIDEtMi40NTItMi40NTEgMi40NDkgMi40NDkgMCAwIDEgMi40NTItMi40NTJaTTExLjY0NSAzMS4yNThjLTIuMDMgMC0zLjY3Ny0xLjYwOS0zLjY3Ny0zLjYgMC0xLjUzMyAyLjE4My00LjYyOCAzLjE4Ny01Ljk2MWEuNjEuNjEgMCAwIDEgLjk4IDBjMS4wMDQgMS4zMzMgMy4xODggNC40MjggMy4xODggNS45NiAwIDEuOTkyLTEuNjQ4IDMuNjAxLTMuNjc4IDMuNjAxWm0xLjIyNi0xMy40ODRhMi40NDkgMi40NDkgMCAwIDEtMi40NTItMi40NTEgMi40NDkgMi40NDkgMCAwIDEgMi40NTItMi40NTIgMi40NDkgMi40NDkgMCAwIDEgMi40NTIgMi40NTIgMi40NDkgMi40NDkgMCAwIDEtMi40NTIgMi40NTFabTEzLjA0IDExLjgxNEE4Ljk4OSA4Ljk4OSAwIDAgMCAxOSAyNi4zNTVjLTEuNjI0IDAtMS42MjQtMi40NTIgMC0yLjQ1MiAzLjQwMiAwIDYuNjEyIDEuNTAyIDguNzg4IDQuMTIyIDEuMDU3IDEuMjU3LS44NTkgMi43OTYtMS44NzggMS41NjNaIi8+PC9zdmc+);
|
||||
mask-position: center;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: 5em;
|
||||
width: 5em;
|
||||
height: 5em;
|
||||
}
|
||||
}
|
||||
.wp-block-woocommerce-empty-cart-block > .aligncenter {
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "woocommerce/filled-cart-block",
|
||||
"version": "1.0.0",
|
||||
"title": "Filled Cart",
|
||||
"description": "Contains blocks that are displayed when the cart contains products.",
|
||||
"category": "woocommerce",
|
||||
"supports": {
|
||||
"align": [ "wide" ],
|
||||
"html": false,
|
||||
"multiple": false,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"attributes": {
|
||||
"lock": {
|
||||
"type": "object",
|
||||
"default": {
|
||||
"remove": true,
|
||||
"move": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parent": [ "woocommerce/cart" ],
|
||||
"textdomain": "woocommerce",
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
|
||||
import { innerBlockAreas } from '@woocommerce/blocks-checkout';
|
||||
import { SidebarLayout } from '@woocommerce/base-components/sidebar-layout';
|
||||
import type { TemplateArray } from '@wordpress/blocks';
|
||||
import { useEditorContext } from '@woocommerce/base-context';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
useForcedLayout,
|
||||
getAllowedBlocks,
|
||||
} from '../../../cart-checkout-shared';
|
||||
import './editor.scss';
|
||||
import { useCartBlockContext } from '../../context';
|
||||
|
||||
export const Edit = ( { clientId }: { clientId: string } ): JSX.Element => {
|
||||
const blockProps = useBlockProps();
|
||||
const { currentView } = useEditorContext();
|
||||
const { hasDarkControls } = useCartBlockContext();
|
||||
const allowedBlocks = getAllowedBlocks( innerBlockAreas.FILLED_CART );
|
||||
const defaultTemplate = [
|
||||
[ 'woocommerce/cart-items-block', {}, [] ],
|
||||
[ 'woocommerce/cart-totals-block', {}, [] ],
|
||||
] as TemplateArray;
|
||||
|
||||
useForcedLayout( {
|
||||
clientId,
|
||||
registeredBlocks: allowedBlocks,
|
||||
defaultTemplate,
|
||||
} );
|
||||
return (
|
||||
<div
|
||||
{ ...blockProps }
|
||||
hidden={ currentView !== 'woocommerce/filled-cart-block' }
|
||||
>
|
||||
<SidebarLayout
|
||||
className={ classnames( 'wc-block-cart', {
|
||||
'has-dark-controls': hasDarkControls,
|
||||
} ) }
|
||||
>
|
||||
<InnerBlocks
|
||||
allowedBlocks={ allowedBlocks }
|
||||
template={ defaultTemplate }
|
||||
templateLock="insert"
|
||||
/>
|
||||
</SidebarLayout>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Save = (): JSX.Element => {
|
||||
return (
|
||||
<div { ...useBlockProps.save() }>
|
||||
<InnerBlocks.Content />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
.wp-block-woocommerce-filled-cart-block {
|
||||
.wc-block-components-sidebar-layout {
|
||||
display: block;
|
||||
}
|
||||
.block-editor-block-list__layout {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.wc-block-components-main,
|
||||
.wc-block-components-sidebar,
|
||||
.block-editor-block-list__layout {
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
.wp-block-woocommerce-cart-totals-block,
|
||||
.wp-block-woocommerce-cart-items-block {
|
||||
.block-editor-block-list__layout {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
import { SidebarLayout } from '@woocommerce/base-components/sidebar-layout';
|
||||
import { useStoreCart } from '@woocommerce/base-context/hooks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useCartBlockContext } from '../../context';
|
||||
|
||||
const FrontendBlock = ( {
|
||||
children,
|
||||
className,
|
||||
}: {
|
||||
children: JSX.Element | JSX.Element[];
|
||||
className: string;
|
||||
} ): JSX.Element | null => {
|
||||
const { cartItems, cartIsLoading } = useStoreCart();
|
||||
const { hasDarkControls } = useCartBlockContext();
|
||||
|
||||
if ( cartIsLoading || cartItems.length >= 1 ) {
|
||||
return (
|
||||
<SidebarLayout
|
||||
className={ classnames( 'wc-block-cart', className, {
|
||||
'has-dark-controls': hasDarkControls,
|
||||
} ) }
|
||||
>
|
||||
{ children }
|
||||
</SidebarLayout>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default FrontendBlock;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { filledCart } from '@woocommerce/icons';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { registerBlockType } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { Edit, Save } from './edit';
|
||||
|
||||
registerBlockType( 'woocommerce/filled-cart-block', {
|
||||
icon: {
|
||||
src: (
|
||||
<Icon
|
||||
icon={ filledCart }
|
||||
className="wc-block-editor-components-block-icon"
|
||||
/>
|
||||
),
|
||||
},
|
||||
edit: Edit,
|
||||
save: Save,
|
||||
} );
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './filled-cart-block';
|
||||
import './cart-items-block';
|
||||
import './cart-line-items-block';
|
||||
import './cart-cross-sells-block';
|
||||
import './cart-cross-sells-products';
|
||||
import './cart-totals-block';
|
||||
import './cart-express-payment-block';
|
||||
import './proceed-to-checkout-block';
|
||||
import './empty-cart-block';
|
||||
import './cart-accepted-payment-methods-block';
|
||||
import './cart-order-summary-block';
|
||||
import './cart-order-summary-subtotal';
|
||||
import './cart-order-summary-fee';
|
||||
import './cart-order-summary-discount';
|
||||
import './cart-order-summary-shipping';
|
||||
import './cart-order-summary-coupon-form';
|
||||
import './cart-order-summary-taxes';
|
||||
import './cart-order-summary-heading';
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user