Create schedule sale pricing block (#37567)
* Create schedule sale pricing block * Add auto show/hide and clean fields depending on the initial values * Add validations to From and To dates fields * Add changelog files * Align block with the figma design * Revert linter replacement in the editor global style.scss file * Fix some words typos * Move and rename schedule sale block to the blocks folder * Load datetime format from @wordpress/date instead of using the woo options datastore * Remove the min difference using by moment to compare dates from 'minute' to undefined * Make sure the dates are normalized for comparison
This commit is contained in:
parent
fa4dd90401
commit
8354ae2792
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add product schedule sale pricing block
|
|
@ -47,6 +47,7 @@
|
|||
"@wordpress/compose": "wp-6.0",
|
||||
"@wordpress/core-data": "wp-6.0",
|
||||
"@wordpress/data": "wp-6.0",
|
||||
"@wordpress/date": "wp-6.0",
|
||||
"@wordpress/editor": "wp-6.0",
|
||||
"@wordpress/element": "wp-6.0",
|
||||
"@wordpress/html-entities": "wp-6.0",
|
||||
|
@ -60,6 +61,7 @@
|
|||
"classnames": "^2.3.1",
|
||||
"dompurify": "^2.3.6",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.4",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-router-dom": "^6.3.0"
|
||||
},
|
||||
|
@ -80,6 +82,7 @@
|
|||
"@types/wordpress__components": "^19.10.3",
|
||||
"@types/wordpress__core-data": "^2.4.5",
|
||||
"@types/wordpress__data": "^6.0.2",
|
||||
"@types/wordpress__date": "^3.3.2",
|
||||
"@types/wordpress__editor": "^13.0.0",
|
||||
"@types/wordpress__media-utils": "^3.0.0",
|
||||
"@types/wordpress__plugins": "^3.0.0",
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"$schema": "https://schemas.wp.org/trunk/block.json",
|
||||
"apiVersion": 2,
|
||||
"name": "woocommerce/product-schedule-sale-fields",
|
||||
"title": "Product schedule sale fields",
|
||||
"category": "woocommerce",
|
||||
"description": "The product schedule sale fields.",
|
||||
"keywords": [ "products", "schedule", "sale" ],
|
||||
"textdomain": "default",
|
||||
"attributes": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"__experimentalRole": "content"
|
||||
}
|
||||
},
|
||||
"supports": {
|
||||
"align": false,
|
||||
"html": false,
|
||||
"multiple": true,
|
||||
"reusable": false,
|
||||
"inserter": false,
|
||||
"lock": false
|
||||
},
|
||||
"editorStyle": "file:./editor.css"
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { DateTimePickerControl } from '@woocommerce/components';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { useBlockProps } from '@wordpress/block-editor';
|
||||
import { BlockEditProps } from '@wordpress/blocks';
|
||||
import { ToggleControl } from '@wordpress/components';
|
||||
import { useEntityProp } from '@wordpress/core-data';
|
||||
import { createElement, useEffect, useState } from '@wordpress/element';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import moment from 'moment';
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore We need this to get the datetime format for the DateTimePickerControl.
|
||||
// eslint-disable-next-line @woocommerce/dependency-group
|
||||
import { getSettings } from '@wordpress/date';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ScheduleSalePricingBlockAttributes } from './types';
|
||||
import { useValidation } from '../../hooks/use-validation';
|
||||
|
||||
export function Edit( {}: BlockEditProps< ScheduleSalePricingBlockAttributes > ) {
|
||||
const blockProps = useBlockProps( {
|
||||
className: 'wp-block-woocommerce-product-schedule-sale-fields',
|
||||
} );
|
||||
|
||||
const dateTimeFormat = getSettings().formats.datetime;
|
||||
|
||||
const [ showScheduleSale, setShowScheduleSale ] = useState( false );
|
||||
|
||||
const [ salePrice ] = useEntityProp< string | null >(
|
||||
'postType',
|
||||
'product',
|
||||
'sale_price'
|
||||
);
|
||||
|
||||
const isSalePriceGreaterThanZero =
|
||||
Number.parseFloat( salePrice || '0' ) > 0;
|
||||
|
||||
const [ dateOnSaleFromGmt, setDateOnSaleFromGmt ] = useEntityProp<
|
||||
string | null
|
||||
>( 'postType', 'product', 'date_on_sale_from_gmt' );
|
||||
|
||||
const [ dateOnSaleToGmt, setDateOnSaleToGmt ] = useEntityProp<
|
||||
string | null
|
||||
>( 'postType', 'product', 'date_on_sale_to_gmt' );
|
||||
|
||||
const today = moment().startOf( 'minute' ).toISOString();
|
||||
|
||||
function handleToggleChange( value: boolean ) {
|
||||
recordEvent( 'product_pricing_schedule_sale_toggle_click', {
|
||||
enabled: value,
|
||||
} );
|
||||
|
||||
setShowScheduleSale( value );
|
||||
|
||||
if ( value ) {
|
||||
setDateOnSaleFromGmt( today );
|
||||
setDateOnSaleToGmt( '' );
|
||||
} else {
|
||||
setDateOnSaleFromGmt( '' );
|
||||
setDateOnSaleToGmt( '' );
|
||||
}
|
||||
}
|
||||
|
||||
// Hide and clean date fields if the user manually change
|
||||
// the sale price to zero or less.
|
||||
useEffect( () => {
|
||||
if ( ! isSalePriceGreaterThanZero ) {
|
||||
setShowScheduleSale( false );
|
||||
setDateOnSaleFromGmt( '' );
|
||||
setDateOnSaleToGmt( '' );
|
||||
}
|
||||
}, [ isSalePriceGreaterThanZero ] );
|
||||
|
||||
// Automatically show date fields if `from` or `to` dates have
|
||||
// any value.
|
||||
useEffect( () => {
|
||||
if ( dateOnSaleFromGmt || dateOnSaleToGmt ) {
|
||||
setShowScheduleSale( true );
|
||||
}
|
||||
}, [ dateOnSaleFromGmt, dateOnSaleToGmt ] );
|
||||
|
||||
const isDateOnSaleToGmtValid = useValidation(
|
||||
'product/date_on_sale_to_gmt',
|
||||
() =>
|
||||
! showScheduleSale ||
|
||||
! dateOnSaleToGmt ||
|
||||
moment( dateOnSaleFromGmt ).isBefore( dateOnSaleToGmt )
|
||||
);
|
||||
|
||||
return (
|
||||
<div { ...blockProps }>
|
||||
<ToggleControl
|
||||
label={ __( 'Schedule sale', 'woocommerce' ) }
|
||||
checked={ showScheduleSale }
|
||||
onChange={ handleToggleChange }
|
||||
disabled={ ! isSalePriceGreaterThanZero }
|
||||
/>
|
||||
|
||||
{ showScheduleSale && (
|
||||
<div className="wp-block-columns">
|
||||
<div className="wp-block-column">
|
||||
<DateTimePickerControl
|
||||
label={ __( 'From', 'woocommerce' ) }
|
||||
placeholder={ __(
|
||||
'Sale start date and time (optional)',
|
||||
'woocommerce'
|
||||
) }
|
||||
dateTimeFormat={ dateTimeFormat }
|
||||
currentDate={ dateOnSaleFromGmt }
|
||||
onChange={ setDateOnSaleFromGmt }
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="wp-block-column">
|
||||
<DateTimePickerControl
|
||||
label={ __( 'To', 'woocommerce' ) }
|
||||
placeholder={ __(
|
||||
'Sale end date and time (optional)',
|
||||
'woocommerce'
|
||||
) }
|
||||
dateTimeFormat={ dateTimeFormat }
|
||||
currentDate={ dateOnSaleToGmt }
|
||||
onChange={ ( value ) =>
|
||||
setDateOnSaleToGmt(
|
||||
moment( value )
|
||||
.startOf( 'minute' )
|
||||
.toISOString()
|
||||
)
|
||||
}
|
||||
className={
|
||||
isDateOnSaleToGmtValid ? undefined : 'has-error'
|
||||
}
|
||||
help={
|
||||
isDateOnSaleToGmtValid
|
||||
? undefined
|
||||
: __(
|
||||
'To date must be greater than From date.',
|
||||
'woocommerce'
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
.wp-block-woocommerce-product-schedule-sale-fields {
|
||||
.components-toggle-control__label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.woocommerce-date-time-picker-control.has-error {
|
||||
.components-base-control .components-input-control__backdrop {
|
||||
border-color: $studio-red-50;
|
||||
}
|
||||
|
||||
.components-base-control__help {
|
||||
color: $studio-red-50;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { createElement } from '@wordpress/element';
|
||||
import { BlockConfiguration } from '@wordpress/blocks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { initBlock } from '../../utils/init-blocks';
|
||||
import blockConfiguration from './block.json';
|
||||
import { Edit } from './edit';
|
||||
import { ScheduleSalePricingBlockAttributes } from './types';
|
||||
|
||||
const { name, ...metadata } =
|
||||
blockConfiguration as BlockConfiguration< ScheduleSalePricingBlockAttributes >;
|
||||
|
||||
export { metadata, name };
|
||||
|
||||
export const settings: Partial<
|
||||
BlockConfiguration< ScheduleSalePricingBlockAttributes >
|
||||
> = {
|
||||
example: {},
|
||||
edit: Edit,
|
||||
};
|
||||
|
||||
export function init() {
|
||||
return initBlock( { name, metadata, settings } );
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { BlockAttributes } from '@wordpress/blocks';
|
||||
|
||||
export interface ScheduleSalePricingBlockAttributes extends BlockAttributes {
|
||||
name: string;
|
||||
}
|
|
@ -20,6 +20,7 @@ import { init as initSection } from '../section';
|
|||
import { init as initTab } from '../tab';
|
||||
import { init as initPricing } from '../pricing-block';
|
||||
import { init as initCollapsible } from '../collapsible-block';
|
||||
import { init as initScheduleSale } from '../../blocks/schedule-sale';
|
||||
|
||||
export const initBlocks = () => {
|
||||
const coreBlocks = __experimentalGetCoreBlocks();
|
||||
|
@ -38,4 +39,5 @@ export const initBlocks = () => {
|
|||
initTab();
|
||||
initPricing();
|
||||
initCollapsible();
|
||||
initScheduleSale();
|
||||
};
|
||||
|
|
|
@ -47,3 +47,5 @@ export const VARIANT_SHIPPING_SECTION_BASIC_ID = `variant/${ SHIPPING_SECTION_BA
|
|||
export const VARIANT_SHIPPING_SECTION_DIMENSIONS_ID = `variant/${ SHIPPING_SECTION_DIMENSIONS_ID }`;
|
||||
|
||||
export const PRODUCT_DETAILS_SLUG = 'product-details';
|
||||
|
||||
export const PRODUCT_SCHEDULED_SALE_SLUG = 'product-scheduled-sale';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@import 'blocks/schedule-sale/editor.scss';
|
||||
@import 'components/editor/style.scss';
|
||||
@import 'components/product-section-layout/style.scss';
|
||||
@import 'components/edit-product-link-modal/style.scss';
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add product schedule sale pricing block to blocks template definition
|
|
@ -513,6 +513,9 @@ class WC_Post_Types {
|
|||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'woocommerce/product-schedule-sale-fields',
|
||||
),
|
||||
array(
|
||||
'woocommerce/product-radio',
|
||||
array(
|
||||
|
|
438
pnpm-lock.yaml
438
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue