/** * External dependencies */ import { __, sprintf } from '@wordpress/i18n'; import FormattedMonetaryAmount from '@woocommerce/base-components/formatted-monetary-amount'; import classNames from 'classnames'; import { formatPrice } from '@woocommerce/price-format'; import { createInterpolateElement } from '@wordpress/element'; import type { Currency } from '@woocommerce/types'; /** * Internal dependencies */ import './style.scss'; interface PriceRangeProps { /** * Currency configuration object */ currency: Currency | Record< string, never >; /** * The maximum price for the range */ maxPrice: string | number; /** * The minimum price for the range */ minPrice: string | number; /** * CSS class applied to each of the elements containing the prices * * **Note:** this excludes the dash in between the elements */ priceClassName?: string; /** * Any custom style to be applied to each of the elements containing the prices * * **Note:** this excludes the dash in between the elements */ priceStyle?: React.CSSProperties; } const PriceRange = ( { currency, maxPrice, minPrice, priceClassName, priceStyle = {}, }: PriceRangeProps ) => { return ( <> { sprintf( /* translators: %1$s min price, %2$s max price */ __( 'Price between %1$s and %2$s', 'woo-gutenberg-products-block' ), formatPrice( minPrice ), formatPrice( maxPrice ) ) }  —  ); }; interface SalePriceProps { /** * Currency configuration object */ currency: Currency | Record< string, never >; /** * CSS class to be applied to the regular price container * * i.e. `` element */ regularPriceClassName?: string; /** * Custom style to be applied to the regular price container * * i.e. `` element */ regularPriceStyle?: React.CSSProperties; /** * The regular price before the sale */ regularPrice: number | string; /** * CSS class to be applied to the sale price container * * i.e. `` element */ priceClassName?: string; /** * Custom style to be applied to the regular price container * * i.e. `` element */ priceStyle?: React.CSSProperties; /** * The new price during the sale */ price: number | string; } const SalePrice = ( { currency, regularPriceClassName, regularPriceStyle, regularPrice, priceClassName, priceStyle, price, }: SalePriceProps ) => { return ( <> { __( 'Previous price:', 'woo-gutenberg-products-block' ) } ( { value } ) } value={ regularPrice } /> { __( 'Discounted price:', 'woo-gutenberg-products-block' ) } ( { value } ) } value={ price } /> ); }; export interface ProductPriceProps { /** * Where to align the wrapper * * Applies the `wc-block-components-product-price--align-${ align }` utility * class to the wrapper. */ align?: 'left' | 'center' | 'right'; /** * CSS class for the wrapper */ className?: string; /** * Currency configuration object */ currency: Currency | Record< string, never >; /** * The string version of the element to use for the price interpolation * * **Note:** It should contain `` (which is also the default value) */ format: string; /** * The current price */ price: number | string; /** * CSS class for the current price wrapper */ priceClassName?: string; /** * Custom style for the current price */ priceStyle?: React.CSSProperties; /** * The maximum price in a range * * If both `maxPrice` and `minPrice` are set, the component will be rendered * as a `PriceRange` component, otherwise, this value will be ignored. */ maxPrice?: number | string; /** * The minimum price in a range * * If both `maxPrice` and `minPrice` are set, the component will be rendered * as a `PriceRange` component, otherwise, this value will be ignored. */ minPrice?: number | string; /** * The regular price if the item is currently on sale * * If this property exists and is different from the current price, then the * component will be rendered as a `SalePrice` component. */ regularPrice?: number | string; /** * CSS class to apply to the regular price wrapper */ regularPriceClassName?: string; /** * Custom style to apply to the regular price wrapper. */ regularPriceStyle?: React.CSSProperties; } const ProductPrice = ( { align, className, currency, format = '', maxPrice, minPrice, price, priceClassName, priceStyle, regularPrice, regularPriceClassName, regularPriceStyle, }: ProductPriceProps ): JSX.Element => { const wrapperClassName = classNames( className, 'price', 'wc-block-components-product-price', { [ `wc-block-components-product-price--align-${ align }` ]: align, } ); if ( ! format.includes( '' ) ) { format = ''; // eslint-disable-next-line no-console console.error( 'Price formats need to include the `` tag.' ); } const isDiscounted = regularPrice && price !== regularPrice; let priceComponent = ( ); if ( isDiscounted ) { priceComponent = ( ); } else if ( minPrice !== undefined && maxPrice !== undefined ) { priceComponent = ( ); } else if ( price ) { priceComponent = ( ); } return ( { createInterpolateElement( format, { price: priceComponent, } ) } ); }; export default ProductPrice;