/** * External dependencies */ import { __ } from '@wordpress/i18n'; import { AlignmentToolbar, BlockControls, InnerBlocks, InspectorControls, MediaUpload, MediaUploadCheck, PanelColorSettings, withColors, } from '@wordpress/editor'; import { Button, FocalPointPicker, IconButton, PanelBody, Placeholder, RangeControl, ResizableBox, Spinner, ToggleControl, Toolbar, withSpokenMessages, } from '@wordpress/components'; import classnames from 'classnames'; import { Fragment } from '@wordpress/element'; import { compose } from '@wordpress/compose'; import { isEmpty } from 'lodash'; import PropTypes from 'prop-types'; import { MIN_HEIGHT } from '@woocommerce/block-settings'; /** * Internal dependencies */ import ProductControl from '../../components/product-control'; import ErrorPlaceholder from '../../components/error-placeholder'; import { dimRatioToClass, getBackgroundImageStyles } from './utils'; import { getImageSrcFromProduct, getImageIdFromProduct, } from '../../utils/products'; import { withProduct } from '../../hocs'; /** * Component to handle edit mode of "Featured Product". */ const FeaturedProduct = ( { attributes, debouncedSpeak, error, getProduct, isLoading, isSelected, overlayColor, product, setAttributes, setOverlayColor, } ) => { const renderApiError = () => ( ); const renderEditMode = () => { const onDone = () => { setAttributes( { editMode: false } ); debouncedSpeak( __( 'Showing Featured Product block preview.', 'woo-gutenberg-products-block' ) ); }; return ( { getBlockControls() } { __( 'Visually highlight a product or variation and encourage prompt action', 'woo-gutenberg-products-block' ) } { const id = value[ 0 ] ? value[ 0 ].id : 0; setAttributes( { productId: id, mediaId: 0, mediaSrc: '', } ); } } /> { __( 'Done', 'woo-gutenberg-products-block' ) } ); }; const getBlockControls = () => { const { contentAlign, editMode } = attributes; const mediaId = attributes.mediaId || getImageIdFromProduct( product ); return ( { setAttributes( { contentAlign: nextAlign } ); } } /> { setAttributes( { mediaId: media.id, mediaSrc: media.url, } ); } } allowedTypes={ [ 'image' ] } value={ mediaId } render={ ( { open } ) => ( ) } /> setAttributes( { editMode: ! editMode } ), isActive: editMode, }, ] } /> ); }; const getInspectorControls = () => { const url = attributes.mediaSrc || getImageSrcFromProduct( product ); const { focalPoint = { x: 0.5, y: 0.5 } } = attributes; // FocalPointPicker was introduced in Gutenberg 5.0 (WordPress 5.2), // so we need to check if it exists before using it. const focalPointPickerExists = typeof FocalPointPicker === 'function'; return ( setAttributes( { showDesc: ! attributes.showDesc } ) } /> setAttributes( { showPrice: ! attributes.showPrice } ) } /> { !! url && ( setAttributes( { dimRatio: ratio } ) } min={ 0 } max={ 100 } step={ 10 } /> { focalPointPickerExists && ( setAttributes( { focalPoint: value } ) } /> ) } ) } ); }; const renderProduct = () => { const { className, contentAlign, dimRatio, focalPoint, height, showDesc, showPrice, } = attributes; const classes = classnames( 'wc-block-featured-product', { 'is-selected': isSelected, 'is-loading': ! product && isLoading, 'is-not-found': ! product && ! isLoading, 'has-background-dim': dimRatio !== 0, }, dimRatioToClass( dimRatio ), contentAlign !== 'center' && `has-${ contentAlign }-content`, className ); const style = getBackgroundImageStyles( attributes.mediaSrc || product ); if ( overlayColor.color ) { style.backgroundColor = overlayColor.color; } if ( focalPoint ) { const bgPosX = focalPoint.x * 100; const bgPosY = focalPoint.y * 100; style.backgroundPosition = `${ bgPosX }% ${ bgPosY }%`; } const onResizeStop = ( event, direction, elt ) => { setAttributes( { height: parseInt( elt.style.height ) } ); }; return ( { ! isEmpty( product.variation ) && ( ) } { showDesc && ( ) } { showPrice && ( ) } ); }; const renderNoProduct = () => ( { isLoading ? ( ) : ( __( 'No product is selected.', 'woo-gutenberg-products-block' ) ) } ); const { editMode } = attributes; if ( error ) { return renderApiError(); } if ( editMode ) { return renderEditMode(); } return ( { getBlockControls() } { getInspectorControls() } { product ? renderProduct() : renderNoProduct() } ); }; FeaturedProduct.propTypes = { /** * The attributes for this block. */ attributes: PropTypes.object.isRequired, /** * Whether this block is currently active. */ isSelected: PropTypes.bool.isRequired, /** * The register block name. */ name: PropTypes.string.isRequired, /** * A callback to update attributes. */ setAttributes: PropTypes.func.isRequired, // from withProduct error: PropTypes.object, getProduct: PropTypes.func, isLoading: PropTypes.bool, product: PropTypes.shape( { name: PropTypes.node, variation: PropTypes.node, description: PropTypes.node, price_html: PropTypes.node, permalink: PropTypes.string, } ), // from withColors overlayColor: PropTypes.object, setOverlayColor: PropTypes.func.isRequired, // from withSpokenMessages debouncedSpeak: PropTypes.func.isRequired, }; export default compose( [ withProduct, withColors( { overlayColor: 'background-color' } ), withSpokenMessages, ] )( FeaturedProduct );