Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 3f47129

Browse files
committed
add discount block
1 parent f21a926 commit 3f47129

File tree

8 files changed

+192
-2
lines changed

8 files changed

+192
-2
lines changed

assets/js/atomic/blocks/product-elements/price-v2/edit.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ import { useStyleProps } from '@woocommerce/base-hooks';
1515
/**
1616
* Internal dependencies
1717
*/
18-
import { originalPriceName, currentPriceName } from './inner-blocks';
18+
import {
19+
originalPriceName,
20+
currentPriceName,
21+
priceDiscount,
22+
} from './inner-blocks';
1923
import { TEMPLATE } from './template';
2024

2125
interface Attributes {
@@ -134,7 +138,11 @@ const EditBlock = ( {
134138
>
135139
<div className={ parentClassName }>
136140
<InnerBlocks
137-
allowedBlocks={ [ originalPriceName, currentPriceName ] }
141+
allowedBlocks={ [
142+
originalPriceName,
143+
currentPriceName,
144+
priceDiscount,
145+
] }
138146
// todo add template for initial price layout
139147
template={ TEMPLATE }
140148
/>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "woocommerce/discount",
3+
"version": "1.0.0",
4+
"icon": "info",
5+
"title": "Discount",
6+
"description": "Display the discounted amount for a product.",
7+
"category": "woocommerce",
8+
"keywords": [ "WooCommerce" ],
9+
"textdomain": "woo-gutenberg-products-block",
10+
"apiVersion": 2,
11+
"$schema": "https://schemas.wp.org/trunk/block.json"
12+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import type { HTMLAttributes } from 'react';
5+
import classnames from 'classnames';
6+
import { useStyleProps } from '@woocommerce/base-hooks';
7+
import { useInnerBlockLayoutContext } from '@woocommerce/shared-context';
8+
import FormattedMonetaryAmount from '@woocommerce/base-components/formatted-monetary-amount';
9+
10+
/**
11+
* Internal dependencies
12+
*/
13+
import type { PriceProps } from '../../types';
14+
15+
type Props = PriceProps & HTMLAttributes< HTMLDivElement >;
16+
17+
const calculateDiscountAmount = ( originalPrice, currentPrice ) => {
18+
// todo: this assumes currentPrice is lower than originalPrice
19+
return parseInt( originalPrice, 10 ) - parseInt( currentPrice, 10 );
20+
};
21+
22+
const calculateDiscountPercentage = ( originalPrice, currentPrice ) => {
23+
const discountAmount = calculateDiscountAmount(
24+
originalPrice,
25+
currentPrice
26+
);
27+
return Math.floor(
28+
( discountAmount / parseInt( originalPrice, 10 ) ) * 100
29+
);
30+
};
31+
32+
const Block = ( {
33+
attributes,
34+
context,
35+
originalPrice,
36+
currentPrice,
37+
currency,
38+
}: Props ): JSX.Element | null => {
39+
// todo: need to setup discountType and showDiscount as attributes/context
40+
// from the parent block.
41+
const {
42+
className,
43+
discountType = 'percentage',
44+
showDiscount = true,
45+
} = attributes;
46+
const { isDescendentOfSingleProductTemplate = false } = context || {};
47+
const { className: stylesClassName, style } = useStyleProps( attributes );
48+
const { parentClassName } = useInnerBlockLayoutContext();
49+
if ( ! showDiscount ) {
50+
return null;
51+
}
52+
const wrapperClassName = classnames(
53+
className,
54+
{
55+
[ `${ parentClassName }__product-price` ]: parentClassName,
56+
},
57+
stylesClassName
58+
);
59+
const priceClassName = classnames( {
60+
[ `${ parentClassName }__product-price_discount` ]: parentClassName,
61+
} );
62+
// todo: lift all the preview pricing up to the parent block (across all the price inner blocks)
63+
const oPrice = isDescendentOfSingleProductTemplate ? '3000' : originalPrice;
64+
const cPrice = isDescendentOfSingleProductTemplate ? '5000' : currentPrice;
65+
const DisplayedDiscount =
66+
discountType === 'percentage' ? (
67+
<span className={ priceClassName }>
68+
{ calculateDiscountPercentage( oPrice, cPrice ) }%
69+
</span>
70+
) : (
71+
<FormattedMonetaryAmount
72+
className={ priceClassName }
73+
currency={ currency }
74+
value={ calculateDiscountAmount( oPrice, cPrice ).toString() }
75+
/>
76+
);
77+
78+
return (
79+
<span className={ wrapperClassName } style={ style }>
80+
{ DisplayedDiscount }
81+
</span>
82+
);
83+
};
84+
85+
export default Block;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { useBlockProps } from '@wordpress/block-editor';
5+
import type { HTMLAttributes, CSSProperties } from 'react';
6+
import { useProductDataContext } from '@woocommerce/shared-context';
7+
import { getCurrencyFromPriceResponse } from '@woocommerce/price-format';
8+
9+
/**
10+
* Internal dependencies
11+
*/
12+
import DiscountBlock from './block';
13+
14+
interface Attributes {
15+
style: CSSProperties;
16+
}
17+
18+
type Props = {
19+
attributes: Attributes;
20+
context?: { isDescendentOfSingleProductTemplate: boolean };
21+
} & HTMLAttributes< HTMLDivElement >;
22+
23+
const DiscountEdit = ( { attributes, context }: Props ): JSX.Element => {
24+
const blockProps = useBlockProps();
25+
const { product } = useProductDataContext();
26+
const { isDescendentOfSingleProductTemplate = false } = context || {};
27+
const originalPrice = product?.prices?.regular_price;
28+
const currentPrice = product?.prices?.price;
29+
const showPrice = originalPrice && currentPrice !== originalPrice;
30+
const currency = isDescendentOfSingleProductTemplate
31+
? getCurrencyFromPriceResponse()
32+
: getCurrencyFromPriceResponse( product?.prices );
33+
const blockAttrs = {
34+
attributes,
35+
currency,
36+
context,
37+
originalPrice,
38+
currentPrice,
39+
};
40+
return (
41+
<>
42+
{ showPrice && (
43+
<div { ...blockProps }>
44+
<DiscountBlock { ...blockAttrs } />
45+
</div>
46+
) }
47+
</>
48+
);
49+
};
50+
51+
export default DiscountEdit;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { registerBlockType } from '@wordpress/blocks';
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
import edit from './edit';
10+
import sharedConfig from '../../../shared/config';
11+
import metadata from './block.json';
12+
13+
const { ancestor, ...configuration } = sharedConfig;
14+
15+
const blockConfig = {
16+
...configuration,
17+
...metadata,
18+
edit,
19+
supports: {
20+
...configuration.supports,
21+
context: '',
22+
},
23+
};
24+
25+
registerBlockType( metadata.name, blockConfig );
26+
27+
export const BLOCK_NAME = metadata.name;

assets/js/atomic/blocks/product-elements/price-v2/inner-blocks/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
import './original-price/index.ts';
55
import './current-price/index.ts';
6+
import './discount/index.ts';
67

78
export { BLOCK_NAME as originalPriceName } from './original-price/index';
89
export { BLOCK_NAME as currentPriceName } from './current-price/index';
10+
export { BLOCK_NAME as priceDiscount } from './discount/index';

assets/js/atomic/blocks/product-elements/price-v2/template.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ import { InnerBlockTemplate } from '@wordpress/blocks';
66
export const TEMPLATE: InnerBlockTemplate[] = [
77
[ 'woocommerce/original-price', {}, [] ],
88
[ 'woocommerce/current-price', {}, [] ],
9+
[ 'woocommerce/discount', {}, [] ],
910
];

assets/js/atomic/blocks/product-elements/price-v2/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export interface BlockAttributes {
1515

1616
export interface PriceContext {
1717
isDescendentOfSingleProductTemplate: boolean;
18+
// eslint-disable-next-line @typescript-eslint/naming-convention
19+
'woocommerce/withSuperScriptStyle'?: boolean;
1820
}
1921

2022
export interface PriceAttributes {
@@ -26,5 +28,7 @@ export interface PriceProps extends ProductPriceProps {
2628
attributes: PriceAttributes;
2729
context?: PriceContext;
2830
rawPrice?: string;
31+
minPrice?: string;
32+
maxPrice?: string;
2933
priceType: 'original' | 'current';
3034
}

0 commit comments

Comments
 (0)