File "block.js"

Full Path: /home/warrior1/public_html/languages/wp-content/plugins/woocommerce/packages/woocommerce-blocks/assets/js/atomic/blocks/product-elements/image/block.js
File size: 4.27 KB
MIME-type: text/x-java
Charset: utf-8

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import { Fragment } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import classnames from 'classnames';
import { PLACEHOLDER_IMG_SRC } from '@woocommerce/settings';
import {
	useInnerBlockLayoutContext,
	useProductDataContext,
} from '@woocommerce/shared-context';
import {
	useBorderProps,
	useSpacingProps,
	useTypographyProps,
} from '@woocommerce/base-hooks';
import { withProductDataContext } from '@woocommerce/shared-hocs';
import { useStoreEvents } from '@woocommerce/base-context/hooks';

/**
 * Internal dependencies
 */
import ProductSaleBadge from '../sale-badge/block';
import './style.scss';

/**
 * Product Image Block Component.
 *
 * @param {Object}  props                           Incoming props.
 * @param {string}  [props.className]               CSS Class name for the component.
 * @param {string}  [props.imageSizing]             Size of image to use.
 * @param {boolean} [props.showProductLink]         Whether or not to display a link to the product page.
 * @param {boolean} [props.showSaleBadge]           Whether or not to display the on sale badge.
 * @param {string}  [props.saleBadgeAlign]          How should the sale badge be aligned if displayed.
 * @param {boolean} [props.isDescendentOfQueryLoop] Whether or not be a children of Query Loop Block.
 * @return {*} The component.
 */
export const Block = ( props ) => {
	const {
		className,
		imageSizing = 'full-size',
		showProductLink = true,
		showSaleBadge,
		saleBadgeAlign = 'right',
	} = props;

	const { parentClassName } = useInnerBlockLayoutContext();
	const { product, isLoading } = useProductDataContext();

	const { dispatchStoreEvent } = useStoreEvents();

	const typographyProps = useTypographyProps( props );
	const borderProps = useBorderProps( props );
	const spacingProps = useSpacingProps( props );

	if ( ! product.id ) {
		return (
			<div
				className={ classnames(
					className,
					'wc-block-components-product-image',
					{
						[ `${ parentClassName }__product-image` ]:
							parentClassName,
					},
					borderProps.className
				) }
				style={ {
					...typographyProps.style,
					...borderProps.style,
					...spacingProps.style,
				} }
			>
				<ImagePlaceholder />
			</div>
		);
	}
	const hasProductImages = !! product.images.length;
	const image = hasProductImages ? product.images[ 0 ] : null;
	const ParentComponent = showProductLink ? 'a' : Fragment;
	const anchorLabel = sprintf(
		/* translators: %s is referring to the product name */
		__( 'Link to %s', 'woocommerce' ),
		product.name
	);
	const anchorProps = {
		href: product.permalink,
		...( ! hasProductImages && { 'aria-label': anchorLabel } ),
		onClick: () => {
			dispatchStoreEvent( 'product-view-link', {
				product,
			} );
		},
	};

	return (
		<div
			className={ classnames(
				className,
				'wc-block-components-product-image',
				{
					[ `${ parentClassName }__product-image` ]: parentClassName,
				},
				borderProps.className
			) }
			style={ {
				...typographyProps.style,
				...borderProps.style,
				...spacingProps.style,
			} }
		>
			<ParentComponent { ...( showProductLink && anchorProps ) }>
				{ !! showSaleBadge && (
					<ProductSaleBadge
						align={ saleBadgeAlign }
						product={ product }
					/>
				) }
				<Image
					fallbackAlt={ product.name }
					image={ image }
					loaded={ ! isLoading }
					showFullSize={ imageSizing !== 'cropped' }
				/>
			</ParentComponent>
		</div>
	);
};

const ImagePlaceholder = () => {
	return (
		<img src={ PLACEHOLDER_IMG_SRC } alt="" width={ 500 } height={ 500 } />
	);
};

const Image = ( { image, loaded, showFullSize, fallbackAlt } ) => {
	const { thumbnail, src, srcset, sizes, alt } = image || {};
	const imageProps = {
		alt: alt || fallbackAlt,
		hidden: ! loaded,
		src: thumbnail,
		...( showFullSize && { src, srcSet: srcset, sizes } ),
	};

	return (
		<>
			{ imageProps.src && (
				/* eslint-disable-next-line jsx-a11y/alt-text */
				<img data-testid="product-image" { ...imageProps } />
			) }
			{ ! image && <ImagePlaceholder /> }
		</>
	);
};

Block.propTypes = {
	className: PropTypes.string,
	fallbackAlt: PropTypes.string,
	showProductLink: PropTypes.bool,
	showSaleBadge: PropTypes.bool,
	saleBadgeAlign: PropTypes.string,
};

export default withProductDataContext( Block );