[Product Editor] Variation quick actions succeed when sku is inherited from parent (#44017)
This commit is contained in:
parent
081f9d303b
commit
1ea439fb61
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Add PartialProductVariation type, where id is required
|
|
@ -87,6 +87,7 @@ export * from './onboarding/types';
|
||||||
export * from './plugins/types';
|
export * from './plugins/types';
|
||||||
export * from './products/types';
|
export * from './products/types';
|
||||||
export type {
|
export type {
|
||||||
|
PartialProductVariation,
|
||||||
ProductVariation,
|
ProductVariation,
|
||||||
ProductVariationAttribute,
|
ProductVariationAttribute,
|
||||||
ProductVariationImage,
|
ProductVariationImage,
|
||||||
|
|
|
@ -57,25 +57,29 @@ export interface ProductVariationImage {
|
||||||
export type ProductVariation = Omit<
|
export type ProductVariation = Omit<
|
||||||
Product,
|
Product,
|
||||||
'slug' | 'attributes' | 'images' | 'manage_stock'
|
'slug' | 'attributes' | 'images' | 'manage_stock'
|
||||||
> & {
|
> &
|
||||||
attributes: ProductVariationAttribute[];
|
Pick< Product, 'id' > & {
|
||||||
/**
|
attributes: ProductVariationAttribute[];
|
||||||
* Variation image data.
|
/**
|
||||||
*/
|
* Variation image data.
|
||||||
image?: ProductVariationImage;
|
*/
|
||||||
/**
|
image?: ProductVariationImage;
|
||||||
* Stock management at variation level. It can have a
|
/**
|
||||||
* 'parent' value if the parent product is managing
|
* Stock management at variation level. It can have a
|
||||||
* the stock at the time the variation was created.
|
* 'parent' value if the parent product is managing
|
||||||
*
|
* the stock at the time the variation was created.
|
||||||
* @default false
|
*
|
||||||
*/
|
* @default false
|
||||||
manage_stock: boolean | 'parent';
|
*/
|
||||||
/**
|
manage_stock: boolean | 'parent';
|
||||||
* The product id this variation belongs to
|
/**
|
||||||
*/
|
* The product id this variation belongs to
|
||||||
parent_id: number;
|
*/
|
||||||
};
|
parent_id: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PartialProductVariation = Partial< ProductVariation > &
|
||||||
|
Pick< ProductVariation, 'id' >;
|
||||||
|
|
||||||
type Query = Omit< ProductQuery, 'name' >;
|
type Query = Omit< ProductQuery, 'name' >;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: fix
|
||||||
|
|
||||||
|
Variation quick actions update properly when variation inherits sku of parent; slot fills always deal with arrays
|
|
@ -4,8 +4,8 @@
|
||||||
import { sprintf, __ } from '@wordpress/i18n';
|
import { sprintf, __ } from '@wordpress/i18n';
|
||||||
import {
|
import {
|
||||||
EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME,
|
EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME,
|
||||||
|
PartialProductVariation,
|
||||||
Product,
|
Product,
|
||||||
ProductVariation,
|
|
||||||
useUserPreferences,
|
useUserPreferences,
|
||||||
} from '@woocommerce/data';
|
} from '@woocommerce/data';
|
||||||
import { useWooBlockProps } from '@woocommerce/block-templates';
|
import { useWooBlockProps } from '@woocommerce/block-templates';
|
||||||
|
@ -115,14 +115,14 @@ export function Edit( {
|
||||||
);
|
);
|
||||||
|
|
||||||
function onSetPrices(
|
function onSetPrices(
|
||||||
handleUpdateAll: ( update: Partial< ProductVariation >[] ) => void
|
handleUpdateAll: ( update: PartialProductVariation[] ) => void
|
||||||
) {
|
) {
|
||||||
recordEvent( 'product_variations_set_prices_select', {
|
recordEvent( 'product_variations_set_prices_select', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
} );
|
} );
|
||||||
const productVariationsListPromise = resolveSelect(
|
const productVariationsListPromise = resolveSelect(
|
||||||
EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME
|
EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME
|
||||||
).getProductVariations< Pick< ProductVariation, 'id' >[] >( {
|
).getProductVariations< PartialProductVariation[] >( {
|
||||||
product_id: productId,
|
product_id: productId,
|
||||||
order: 'asc',
|
order: 'asc',
|
||||||
orderby: 'menu_order',
|
orderby: 'menu_order',
|
||||||
|
|
|
@ -31,15 +31,11 @@ export function DownloadsMenuItem( {
|
||||||
onClose,
|
onClose,
|
||||||
supportsMultipleSelection = false,
|
supportsMultipleSelection = false,
|
||||||
}: VariationActionsMenuItemProps ) {
|
}: VariationActionsMenuItemProps ) {
|
||||||
const ids = Array.isArray( selection )
|
const ids = selection.map( ( { id } ) => id );
|
||||||
? selection.map( ( { id } ) => id )
|
|
||||||
: selection.id;
|
|
||||||
|
|
||||||
const downloadsIds: number[] = (
|
const downloadsIds: number[] = selection[ 0 ].downloads.map(
|
||||||
Array.isArray( selection )
|
( { id }: ProductDownload ) => Number.parseInt( id, 10 )
|
||||||
? selection[ 0 ].downloads
|
);
|
||||||
: selection.downloads
|
|
||||||
).map( ( { id }: ProductDownload ) => Number.parseInt( id, 10 ) );
|
|
||||||
|
|
||||||
const [ uploadFilesModalOpen, setUploadFilesModalOpen ] = useState( false );
|
const [ uploadFilesModalOpen, setUploadFilesModalOpen ] = useState( false );
|
||||||
|
|
||||||
|
@ -55,16 +51,12 @@ export function DownloadsMenuItem( {
|
||||||
downloads,
|
downloads,
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
...partialVariation,
|
||||||
...partialVariation,
|
id,
|
||||||
id,
|
} ) )
|
||||||
} ) )
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( partialVariation );
|
|
||||||
}
|
|
||||||
|
|
||||||
recordEvent( 'product_variations_menu_downloads_update', {
|
recordEvent( 'product_variations_menu_downloads_update', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
|
@ -98,20 +90,13 @@ export function DownloadsMenuItem( {
|
||||||
handlePrompt( {
|
handlePrompt( {
|
||||||
message,
|
message,
|
||||||
onOk( value ) {
|
onOk( value ) {
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
downloadable: true,
|
|
||||||
[ name ]: value,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
downloadable: true,
|
downloadable: true,
|
||||||
[ name ]: value,
|
[ name ]: value,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
recordEvent( 'product_variations_menu_downloads_update', {
|
recordEvent( 'product_variations_menu_downloads_update', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: `${ name }_set`,
|
action: `${ name }_set`,
|
||||||
|
|
|
@ -23,9 +23,7 @@ export function InventoryMenuItem( {
|
||||||
onClose,
|
onClose,
|
||||||
supportsMultipleSelection = false,
|
supportsMultipleSelection = false,
|
||||||
}: VariationActionsMenuItemProps ) {
|
}: VariationActionsMenuItemProps ) {
|
||||||
const ids = Array.isArray( selection )
|
const ids = selection.map( ( { id } ) => id );
|
||||||
? selection.map( ( { id } ) => id )
|
|
||||||
: selection.id;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
@ -70,20 +68,14 @@ export function InventoryMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map(
|
||||||
selection.map(
|
( { id, manage_stock } ) => ( {
|
||||||
( { id, manage_stock } ) => ( {
|
id,
|
||||||
id,
|
manage_stock: ! manage_stock,
|
||||||
manage_stock: ! manage_stock,
|
} )
|
||||||
} )
|
)
|
||||||
)
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
manage_stock: ! selection.manage_stock,
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
onClose();
|
onClose();
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
|
@ -99,22 +91,14 @@ export function InventoryMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
stock_status:
|
|
||||||
PRODUCT_STOCK_STATUS_KEYS.instock,
|
|
||||||
manage_stock: false,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
stock_status:
|
stock_status:
|
||||||
PRODUCT_STOCK_STATUS_KEYS.instock,
|
PRODUCT_STOCK_STATUS_KEYS.instock,
|
||||||
manage_stock: false,
|
manage_stock: false,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
onClose();
|
onClose();
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
|
@ -130,22 +114,14 @@ export function InventoryMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
stock_status:
|
|
||||||
PRODUCT_STOCK_STATUS_KEYS.outofstock,
|
|
||||||
manage_stock: false,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
stock_status:
|
stock_status:
|
||||||
PRODUCT_STOCK_STATUS_KEYS.outofstock,
|
PRODUCT_STOCK_STATUS_KEYS.outofstock,
|
||||||
manage_stock: false,
|
manage_stock: false,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
onClose();
|
onClose();
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
|
@ -164,22 +140,14 @@ export function InventoryMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
stock_status:
|
|
||||||
PRODUCT_STOCK_STATUS_KEYS.onbackorder,
|
|
||||||
manage_stock: false,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
stock_status:
|
stock_status:
|
||||||
PRODUCT_STOCK_STATUS_KEYS.onbackorder,
|
PRODUCT_STOCK_STATUS_KEYS.onbackorder,
|
||||||
manage_stock: false,
|
manage_stock: false,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
onClose();
|
onClose();
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
|
@ -212,22 +180,14 @@ export function InventoryMenuItem( {
|
||||||
if ( Number.isNaN( lowStockAmount ) ) {
|
if ( Number.isNaN( lowStockAmount ) ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
low_stock_amount:
|
|
||||||
lowStockAmount,
|
|
||||||
manage_stock: true,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
low_stock_amount:
|
low_stock_amount:
|
||||||
lowStockAmount,
|
lowStockAmount,
|
||||||
manage_stock: true,
|
manage_stock: true,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
|
|
@ -61,9 +61,7 @@ export function PricingMenuItem( {
|
||||||
onClose,
|
onClose,
|
||||||
supportsMultipleSelection = false,
|
supportsMultipleSelection = false,
|
||||||
}: VariationActionsMenuItemProps ) {
|
}: VariationActionsMenuItemProps ) {
|
||||||
const ids = Array.isArray( selection )
|
const ids = selection.map( ( { id } ) => id );
|
||||||
? selection.map( ( { id } ) => id )
|
|
||||||
: selection.id;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
@ -119,31 +117,18 @@ export function PricingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map(
|
||||||
selection.map(
|
( { id, regular_price } ) => ( {
|
||||||
( {
|
id,
|
||||||
id,
|
regular_price:
|
||||||
regular_price,
|
addFixedOrPercentage(
|
||||||
} ) => ( {
|
regular_price,
|
||||||
id,
|
value
|
||||||
regular_price:
|
)?.toFixed( 2 ),
|
||||||
addFixedOrPercentage(
|
} )
|
||||||
regular_price,
|
)
|
||||||
value
|
);
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
regular_price:
|
|
||||||
addFixedOrPercentage(
|
|
||||||
selection.regular_price,
|
|
||||||
value
|
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -175,33 +160,19 @@ export function PricingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map(
|
||||||
selection.map(
|
( { id, regular_price } ) => ( {
|
||||||
( {
|
id,
|
||||||
id,
|
regular_price:
|
||||||
regular_price,
|
addFixedOrPercentage(
|
||||||
} ) => ( {
|
regular_price,
|
||||||
id,
|
value,
|
||||||
regular_price:
|
-1
|
||||||
addFixedOrPercentage(
|
)?.toFixed( 2 ),
|
||||||
regular_price,
|
} )
|
||||||
value,
|
)
|
||||||
-1
|
);
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
regular_price:
|
|
||||||
addFixedOrPercentage(
|
|
||||||
selection.regular_price,
|
|
||||||
value,
|
|
||||||
-1
|
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -231,18 +202,12 @@ export function PricingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
sale_price: value,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
sale_price: value,
|
sale_price: value,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -274,31 +239,18 @@ export function PricingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map(
|
||||||
selection.map(
|
( { id, sale_price } ) => ( {
|
||||||
( {
|
id,
|
||||||
id,
|
sale_price:
|
||||||
sale_price,
|
addFixedOrPercentage(
|
||||||
} ) => ( {
|
sale_price,
|
||||||
id,
|
value
|
||||||
sale_price:
|
)?.toFixed( 2 ),
|
||||||
addFixedOrPercentage(
|
} )
|
||||||
sale_price,
|
)
|
||||||
value
|
);
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
sale_price:
|
|
||||||
addFixedOrPercentage(
|
|
||||||
selection.sale_price,
|
|
||||||
value
|
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -330,33 +282,19 @@ export function PricingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map(
|
||||||
selection.map(
|
( { id, sale_price } ) => ( {
|
||||||
( {
|
id,
|
||||||
id,
|
sale_price:
|
||||||
sale_price,
|
addFixedOrPercentage(
|
||||||
} ) => ( {
|
sale_price,
|
||||||
id,
|
value,
|
||||||
sale_price:
|
-1
|
||||||
addFixedOrPercentage(
|
)?.toFixed( 2 ),
|
||||||
sale_price,
|
} )
|
||||||
value,
|
)
|
||||||
-1
|
);
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
sale_price:
|
|
||||||
addFixedOrPercentage(
|
|
||||||
selection.sale_price,
|
|
||||||
value,
|
|
||||||
-1
|
|
||||||
)?.toFixed( 2 ),
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
@ -388,19 +326,12 @@ export function PricingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
date_on_sale_from_gmt:
|
|
||||||
value,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
date_on_sale_from_gmt: value,
|
date_on_sale_from_gmt: value,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
handlePrompt( {
|
handlePrompt( {
|
||||||
|
@ -417,18 +348,12 @@ export function PricingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
date_on_sale_to_gmt: value,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
date_on_sale_to_gmt: value,
|
date_on_sale_to_gmt: value,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
|
|
@ -21,9 +21,7 @@ export function SetListPriceMenuItem( {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
const ids = Array.isArray( selection )
|
const ids = selection.map( ( { id } ) => id );
|
||||||
? selection.map( ( { id } ) => id )
|
|
||||||
: selection.id;
|
|
||||||
|
|
||||||
recordEvent( 'product_variations_menu_pricing_select', {
|
recordEvent( 'product_variations_menu_pricing_select', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
|
@ -37,18 +35,12 @@ export function SetListPriceMenuItem( {
|
||||||
action: 'list_price_set',
|
action: 'list_price_set',
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
} );
|
} );
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
regular_price: value,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
regular_price: value,
|
regular_price: value,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
|
|
@ -22,31 +22,20 @@ export function ShippingMenuItem( {
|
||||||
onClose,
|
onClose,
|
||||||
supportsMultipleSelection = false,
|
supportsMultipleSelection = false,
|
||||||
}: VariationActionsMenuItemProps ) {
|
}: VariationActionsMenuItemProps ) {
|
||||||
const ids = Array.isArray( selection )
|
const ids = selection.map( ( { id } ) => id );
|
||||||
? selection.map( ( { id } ) => id )
|
|
||||||
: selection.id;
|
|
||||||
|
|
||||||
function handleDimensionsChange(
|
function handleDimensionsChange(
|
||||||
value: Partial< ProductVariation[ 'dimensions' ] >
|
value: Partial< ProductVariation[ 'dimensions' ] >
|
||||||
) {
|
) {
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id, dimensions } ) => ( {
|
||||||
selection.map( ( { id, dimensions } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
dimensions: {
|
|
||||||
...dimensions,
|
|
||||||
...value,
|
|
||||||
},
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
dimensions: {
|
dimensions: {
|
||||||
...selection.dimensions,
|
...dimensions,
|
||||||
...value,
|
...value,
|
||||||
},
|
},
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -87,20 +76,14 @@ export function ShippingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map(
|
||||||
selection.map(
|
( { id, virtual } ) => ( {
|
||||||
( { id, virtual } ) => ( {
|
id,
|
||||||
id,
|
virtual: ! virtual,
|
||||||
virtual: ! virtual,
|
} )
|
||||||
} )
|
)
|
||||||
)
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
virtual: ! selection.virtual,
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
recordEvent(
|
recordEvent(
|
||||||
'product_variations_menu_shipping_update',
|
'product_variations_menu_shipping_update',
|
||||||
{
|
{
|
||||||
|
@ -225,16 +208,12 @@ export function ShippingMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
weight: value,
|
||||||
weight: value,
|
} ) )
|
||||||
} ) )
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( { weight: value } );
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
|
|
@ -22,9 +22,7 @@ export function ToggleVisibilityMenuItem( {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMenuItemClick() {
|
function handleMenuItemClick() {
|
||||||
const ids = Array.isArray( selection )
|
const ids = selection.map( ( { id } ) => id );
|
||||||
? selection.map( ( { id } ) => id )
|
|
||||||
: selection.id;
|
|
||||||
|
|
||||||
recordEvent( 'product_variations_menu_toggle_visibility_select', {
|
recordEvent( 'product_variations_menu_toggle_visibility_select', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
|
@ -32,18 +30,12 @@ export function ToggleVisibilityMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id, status } ) => ( {
|
||||||
selection.map( ( { id, status } ) => ( {
|
id,
|
||||||
id,
|
status: toggleStatus( status ),
|
||||||
status: toggleStatus( status ),
|
} ) )
|
||||||
} ) )
|
);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
status: toggleStatus( selection.status ),
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
recordEvent( 'product_variations_toggle_visibility_update', {
|
recordEvent( 'product_variations_toggle_visibility_update', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { ProductVariation } from '@woocommerce/data';
|
import { PartialProductVariation, ProductVariation } from '@woocommerce/data';
|
||||||
|
|
||||||
export type VariationActionsMenuItemProps = {
|
export type VariationActionsMenuItemProps = {
|
||||||
selection: ProductVariation | ProductVariation[];
|
selection: ProductVariation[];
|
||||||
onChange(
|
onChange( values: PartialProductVariation[] ): void;
|
||||||
variation: Partial< ProductVariation > | Partial< ProductVariation >[]
|
|
||||||
): void;
|
|
||||||
onClose(): void;
|
onClose(): void;
|
||||||
supportsMultipleSelection?: boolean;
|
supportsMultipleSelection?: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,9 +21,7 @@ export function UpdateStockMenuItem( {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
const ids = Array.isArray( selection )
|
const ids = selection.map( ( { id } ) => id );
|
||||||
? selection.map( ( { id } ) => id )
|
|
||||||
: selection.id;
|
|
||||||
|
|
||||||
recordEvent( 'product_variations_menu_inventory_select', {
|
recordEvent( 'product_variations_menu_inventory_select', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
|
@ -44,20 +42,13 @@ export function UpdateStockMenuItem( {
|
||||||
variation_id: ids,
|
variation_id: ids,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( Array.isArray( selection ) ) {
|
onChange(
|
||||||
onChange(
|
selection.map( ( { id } ) => ( {
|
||||||
selection.map( ( { id } ) => ( {
|
id,
|
||||||
id,
|
|
||||||
stock_quantity: stockQuantity,
|
|
||||||
manage_stock: true,
|
|
||||||
} ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onChange( {
|
|
||||||
stock_quantity: stockQuantity,
|
stock_quantity: stockQuantity,
|
||||||
manage_stock: true,
|
manage_stock: true,
|
||||||
} );
|
} ) )
|
||||||
}
|
);
|
||||||
},
|
},
|
||||||
} );
|
} );
|
||||||
onClose();
|
onClose();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME,
|
EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME,
|
||||||
|
PartialProductVariation,
|
||||||
ProductAttribute,
|
ProductAttribute,
|
||||||
ProductVariation,
|
ProductVariation,
|
||||||
} from '@woocommerce/data';
|
} from '@woocommerce/data';
|
||||||
|
@ -251,7 +252,7 @@ export function useVariations( { productId }: UseVariationsProps ) {
|
||||||
async function onUpdate( {
|
async function onUpdate( {
|
||||||
id: variationId,
|
id: variationId,
|
||||||
...variation
|
...variation
|
||||||
}: Partial< ProductVariation > ) {
|
}: PartialProductVariation ) {
|
||||||
if ( isUpdating[ variationId ] ) return;
|
if ( isUpdating[ variationId ] ) return;
|
||||||
|
|
||||||
const { updateProductVariation } = dispatch(
|
const { updateProductVariation } = dispatch(
|
||||||
|
@ -315,7 +316,7 @@ export function useVariations( { productId }: UseVariationsProps ) {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onBatchUpdate( values: Partial< ProductVariation >[] ) {
|
async function onBatchUpdate( values: PartialProductVariation[] ) {
|
||||||
// @ts-expect-error There are no types for this.
|
// @ts-expect-error There are no types for this.
|
||||||
const { invalidateResolution: coreInvalidateResolution } =
|
const { invalidateResolution: coreInvalidateResolution } =
|
||||||
dispatch( 'core' );
|
dispatch( 'core' );
|
||||||
|
@ -376,7 +377,7 @@ export function useVariations( { productId }: UseVariationsProps ) {
|
||||||
return { update: result };
|
return { update: result };
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onBatchDelete( values: Pick< ProductVariation, 'id' >[] ) {
|
async function onBatchDelete( values: PartialProductVariation[] ) {
|
||||||
// @ts-expect-error There are no types for this.
|
// @ts-expect-error There are no types for this.
|
||||||
const { invalidateResolution: coreInvalidateResolution } =
|
const { invalidateResolution: coreInvalidateResolution } =
|
||||||
dispatch( 'core' );
|
dispatch( 'core' );
|
||||||
|
@ -409,7 +410,7 @@ export function useVariations( { productId }: UseVariationsProps ) {
|
||||||
} >(
|
} >(
|
||||||
{ product_id: productId },
|
{ product_id: productId },
|
||||||
{
|
{
|
||||||
delete: subset,
|
delete: subset.map( ( { id } ) => id ),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,10 @@ export function MultipleUpdateMenu( {
|
||||||
onChange,
|
onChange,
|
||||||
onDelete,
|
onDelete,
|
||||||
}: VariationActionsMenuProps ) {
|
}: VariationActionsMenuProps ) {
|
||||||
|
if ( ! selection ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
// @ts-expect-error missing prop in types.
|
// @ts-expect-error missing prop in types.
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { createElement } from '@wordpress/element';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { moreVertical } from '@wordpress/icons';
|
import { moreVertical } from '@wordpress/icons';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
import { ProductVariation } from '@woocommerce/data';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -20,6 +19,10 @@ export function SingleUpdateMenu( {
|
||||||
onChange,
|
onChange,
|
||||||
onDelete,
|
onDelete,
|
||||||
}: VariationActionsMenuProps ) {
|
}: VariationActionsMenuProps ) {
|
||||||
|
if ( ! selection || selection.length !== 1 ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
popoverProps={ {
|
popoverProps={ {
|
||||||
|
@ -32,7 +35,7 @@ export function SingleUpdateMenu( {
|
||||||
onClick() {
|
onClick() {
|
||||||
recordEvent( 'product_variations_menu_view', {
|
recordEvent( 'product_variations_menu_view', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
variation_id: ( selection as ProductVariation ).id,
|
variation_id: selection[ 0 ].id,
|
||||||
} );
|
} );
|
||||||
},
|
},
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -23,7 +23,7 @@ const mockVariation = {
|
||||||
downloads: [],
|
downloads: [],
|
||||||
name: '',
|
name: '',
|
||||||
parent_id: 1,
|
parent_id: 1,
|
||||||
} as ProductVariation;
|
} as unknown as ProductVariation;
|
||||||
|
|
||||||
const anotherMockVariation = {
|
const anotherMockVariation = {
|
||||||
id: 11,
|
id: 11,
|
||||||
|
@ -32,7 +32,7 @@ const anotherMockVariation = {
|
||||||
downloads: [],
|
downloads: [],
|
||||||
name: '',
|
name: '',
|
||||||
parent_id: 1,
|
parent_id: 1,
|
||||||
} as ProductVariation;
|
} as unknown as ProductVariation;
|
||||||
|
|
||||||
describe( 'MultipleUpdateMenu', () => {
|
describe( 'MultipleUpdateMenu', () => {
|
||||||
let onChangeMock: jest.Mock, onDeleteMock: jest.Mock;
|
let onChangeMock: jest.Mock, onDeleteMock: jest.Mock;
|
||||||
|
@ -83,7 +83,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
it( 'should trigger product_variations_menu_view track when dropdown toggled', () => {
|
it( 'should trigger product_variations_menu_view track when dropdown toggled', () => {
|
||||||
const { getByRole } = render(
|
const { getByRole } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ mockVariation }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -101,7 +101,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
it( 'should render dropdown with pricing, inventory, and delete options when opened', () => {
|
it( 'should render dropdown with pricing, inventory, and delete options when opened', () => {
|
||||||
const { queryByText, getByRole } = render(
|
const { queryByText, getByRole } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ mockVariation }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -115,7 +115,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
it( 'should call onDelete when Delete menuItem is clicked', async () => {
|
it( 'should call onDelete when Delete menuItem is clicked', async () => {
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ mockVariation }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -129,7 +129,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
it( 'should open Inventory sub-menu if Inventory is clicked with click track', async () => {
|
it( 'should open Inventory sub-menu if Inventory is clicked with click track', async () => {
|
||||||
const { queryByText, getByRole, getByText } = render(
|
const { queryByText, getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -140,7 +140,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
'product_variations_menu_inventory_click',
|
'product_variations_menu_inventory_click',
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( queryByText( 'Update stock' ) ).toBeInTheDocument();
|
expect( queryByText( 'Update stock' ) ).toBeInTheDocument();
|
||||||
|
@ -156,7 +156,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
window.prompt = jest.fn().mockReturnValue( '10' );
|
window.prompt = jest.fn().mockReturnValue( '10' );
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -170,19 +170,22 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'stock_quantity_set',
|
action: 'stock_quantity_set',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( onChangeMock ).toHaveBeenCalledWith( {
|
expect( onChangeMock ).toHaveBeenCalledWith( [
|
||||||
stock_quantity: 10,
|
{
|
||||||
manage_stock: true,
|
id: 10,
|
||||||
} );
|
stock_quantity: 10,
|
||||||
|
manage_stock: true,
|
||||||
|
},
|
||||||
|
] );
|
||||||
expect( recordEvent ).toHaveBeenCalledWith(
|
expect( recordEvent ).toHaveBeenCalledWith(
|
||||||
'product_variations_menu_inventory_update',
|
'product_variations_menu_inventory_update',
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'stock_quantity_set',
|
action: 'stock_quantity_set',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
|
@ -191,7 +194,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
window.prompt = jest.fn().mockReturnValue( null );
|
window.prompt = jest.fn().mockReturnValue( null );
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -205,7 +208,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'stock_quantity_set',
|
action: 'stock_quantity_set',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( onChangeMock ).not.toHaveBeenCalledWith( {
|
expect( onChangeMock ).not.toHaveBeenCalledWith( {
|
||||||
|
@ -217,7 +220,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'stock_quantity_set',
|
action: 'stock_quantity_set',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
|
@ -225,7 +228,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
it( 'should call onChange with toggled manage_stock when toggle "track quantity" is clicked', async () => {
|
it( 'should call onChange with toggled manage_stock when toggle "track quantity" is clicked', async () => {
|
||||||
const { getByRole, getByText, rerender } = render(
|
const { getByRole, getByText, rerender } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -239,16 +242,19 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'manage_stock_toggle',
|
action: 'manage_stock_toggle',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( onChangeMock ).toHaveBeenCalledWith( {
|
expect( onChangeMock ).toHaveBeenCalledWith( [
|
||||||
manage_stock: true,
|
{
|
||||||
} );
|
id: 10,
|
||||||
|
manage_stock: true,
|
||||||
|
},
|
||||||
|
] );
|
||||||
onChangeMock.mockClear();
|
onChangeMock.mockClear();
|
||||||
rerender(
|
rerender(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation, manage_stock: true } }
|
selection={ [ { ...mockVariation, manage_stock: true } ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -256,15 +262,18 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
await fireEvent.click( getByRole( 'button', { name: 'Actions' } ) );
|
await fireEvent.click( getByRole( 'button', { name: 'Actions' } ) );
|
||||||
await fireEvent.click( getByText( 'Inventory' ) );
|
await fireEvent.click( getByText( 'Inventory' ) );
|
||||||
await fireEvent.click( getByText( 'Toggle "track quantity"' ) );
|
await fireEvent.click( getByText( 'Toggle "track quantity"' ) );
|
||||||
expect( onChangeMock ).toHaveBeenCalledWith( {
|
expect( onChangeMock ).toHaveBeenCalledWith( [
|
||||||
manage_stock: false,
|
{
|
||||||
} );
|
id: 10,
|
||||||
|
manage_stock: false,
|
||||||
|
},
|
||||||
|
] );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should call onChange with toggled stock_status when toggle "Set status to In stock" is clicked', async () => {
|
it( 'should call onChange with toggled stock_status when toggle "Set status to In stock" is clicked', async () => {
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -278,19 +287,22 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'set_status_in_stock',
|
action: 'set_status_in_stock',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( onChangeMock ).toHaveBeenCalledWith( {
|
expect( onChangeMock ).toHaveBeenCalledWith( [
|
||||||
stock_status: PRODUCT_STOCK_STATUS_KEYS.instock,
|
{
|
||||||
manage_stock: false,
|
id: 10,
|
||||||
} );
|
stock_status: PRODUCT_STOCK_STATUS_KEYS.instock,
|
||||||
|
manage_stock: false,
|
||||||
|
},
|
||||||
|
] );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should call onChange with toggled stock_status when toggle "Set status to Out of stock" is clicked', async () => {
|
it( 'should call onChange with toggled stock_status when toggle "Set status to Out of stock" is clicked', async () => {
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -304,19 +316,22 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'set_status_out_of_stock',
|
action: 'set_status_out_of_stock',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( onChangeMock ).toHaveBeenCalledWith( {
|
expect( onChangeMock ).toHaveBeenCalledWith( [
|
||||||
stock_status: PRODUCT_STOCK_STATUS_KEYS.outofstock,
|
{
|
||||||
manage_stock: false,
|
id: 10,
|
||||||
} );
|
stock_status: PRODUCT_STOCK_STATUS_KEYS.outofstock,
|
||||||
|
manage_stock: false,
|
||||||
|
},
|
||||||
|
] );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should call onChange with toggled stock_status when toggle "Set status to On back order" is clicked', async () => {
|
it( 'should call onChange with toggled stock_status when toggle "Set status to On back order" is clicked', async () => {
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -330,20 +345,23 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'set_status_on_back_order',
|
action: 'set_status_on_back_order',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( onChangeMock ).toHaveBeenCalledWith( {
|
expect( onChangeMock ).toHaveBeenCalledWith( [
|
||||||
stock_status: PRODUCT_STOCK_STATUS_KEYS.onbackorder,
|
{
|
||||||
manage_stock: false,
|
id: 10,
|
||||||
} );
|
stock_status: PRODUCT_STOCK_STATUS_KEYS.onbackorder,
|
||||||
|
manage_stock: false,
|
||||||
|
},
|
||||||
|
] );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should call onChange with low_stock_amount when Edit low stock threshold is clicked', async () => {
|
it( 'should call onChange with low_stock_amount when Edit low stock threshold is clicked', async () => {
|
||||||
window.prompt = jest.fn().mockReturnValue( '7' );
|
window.prompt = jest.fn().mockReturnValue( '7' );
|
||||||
const { getByRole, getByText } = render(
|
const { getByRole, getByText } = render(
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ { ...mockVariation } }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -357,13 +375,16 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
{
|
{
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
action: 'low_stock_amount_set',
|
action: 'low_stock_amount_set',
|
||||||
variation_id: 10,
|
variation_id: [ 10 ],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
expect( onChangeMock ).toHaveBeenCalledWith( {
|
expect( onChangeMock ).toHaveBeenCalledWith( [
|
||||||
low_stock_amount: 7,
|
{
|
||||||
manage_stock: true,
|
id: 10,
|
||||||
} );
|
low_stock_amount: 7,
|
||||||
|
manage_stock: true,
|
||||||
|
},
|
||||||
|
] );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -26,7 +26,7 @@ const mockVariation = {
|
||||||
downloads: [],
|
downloads: [],
|
||||||
name: '',
|
name: '',
|
||||||
parent_id: 1,
|
parent_id: 1,
|
||||||
} as ProductVariation;
|
} as unknown as ProductVariation;
|
||||||
|
|
||||||
const anotherMockVariation = {
|
const anotherMockVariation = {
|
||||||
id: 11,
|
id: 11,
|
||||||
|
@ -35,7 +35,7 @@ const anotherMockVariation = {
|
||||||
downloads: [],
|
downloads: [],
|
||||||
name: '',
|
name: '',
|
||||||
parent_id: 1,
|
parent_id: 1,
|
||||||
} as ProductVariation;
|
} as unknown as ProductVariation;
|
||||||
|
|
||||||
describe( 'SingleUpdateMenu', () => {
|
describe( 'SingleUpdateMenu', () => {
|
||||||
let onClickMock: jest.Mock,
|
let onClickMock: jest.Mock,
|
||||||
|
@ -60,7 +60,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
My top level item
|
My top level item
|
||||||
</VariationQuickUpdateMenuItem>
|
</VariationQuickUpdateMenuItem>
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ mockVariation }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -90,7 +90,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
My secondary item
|
My secondary item
|
||||||
</VariationQuickUpdateMenuItem>
|
</VariationQuickUpdateMenuItem>
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ mockVariation }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -120,7 +120,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
My tertiary item
|
My tertiary item
|
||||||
</VariationQuickUpdateMenuItem>
|
</VariationQuickUpdateMenuItem>
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ mockVariation }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
@ -150,7 +150,7 @@ describe( 'SingleUpdateMenu', () => {
|
||||||
My shipping item
|
My shipping item
|
||||||
</VariationQuickUpdateMenuItem>
|
</VariationQuickUpdateMenuItem>
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ mockVariation }
|
selection={ [ mockVariation ] }
|
||||||
onChange={ onChangeMock }
|
onChange={ onChangeMock }
|
||||||
onDelete={ onDeleteMock }
|
onDelete={ onDeleteMock }
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { ProductVariation } from '@woocommerce/data';
|
import { PartialProductVariation, ProductVariation } from '@woocommerce/data';
|
||||||
|
|
||||||
export type VariationActionsMenuProps = {
|
export type VariationActionsMenuProps = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
selection: ProductVariation | ProductVariation[];
|
selection: ProductVariation[];
|
||||||
onChange( variation: Partial< ProductVariation > ): void;
|
onChange( values: PartialProductVariation[] ): void;
|
||||||
onDelete(
|
onDelete( values: PartialProductVariation[] ): void;
|
||||||
variation: ProductVariation | Partial< ProductVariation >[]
|
|
||||||
): void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VariationQuickUpdateSlotProps = {
|
export type VariationQuickUpdateSlotProps = {
|
||||||
group: string;
|
group: string;
|
||||||
supportsMultipleSelection: boolean;
|
supportsMultipleSelection: boolean;
|
||||||
selection: ProductVariation | ProductVariation[];
|
selection: ProductVariation[];
|
||||||
onChange: (
|
onChange: ( values: PartialProductVariation[] ) => void;
|
||||||
variation: Partial< ProductVariation > | Partial< ProductVariation >[]
|
|
||||||
) => void;
|
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,8 +33,6 @@ export type MenuItemProps = {
|
||||||
| 'onClose'
|
| 'onClose'
|
||||||
| 'selection' ]: VariationQuickUpdateSlotProps[ K ];
|
| 'selection' ]: VariationQuickUpdateSlotProps[ K ];
|
||||||
} ) => void;
|
} ) => void;
|
||||||
onChange?: (
|
onChange?: ( values: PartialProductVariation[] ) => void;
|
||||||
variation: Partial< ProductVariation > | Partial< ProductVariation >[]
|
|
||||||
) => void;
|
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { MenuGroup, MenuItem } from '@wordpress/components';
|
||||||
import { createElement, Fragment } from '@wordpress/element';
|
import { createElement, Fragment } from '@wordpress/element';
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
import { ProductVariation } from '@woocommerce/data';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +31,11 @@ export function VariationActions( {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
supportsMultipleSelection: boolean;
|
supportsMultipleSelection: boolean;
|
||||||
} ) {
|
} ) {
|
||||||
|
const singleSelection =
|
||||||
|
! supportsMultipleSelection && selection.length === 1
|
||||||
|
? selection[ 0 ]
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={ classNames( {
|
className={ classNames( {
|
||||||
|
@ -45,7 +49,7 @@ export function VariationActions( {
|
||||||
: sprintf(
|
: sprintf(
|
||||||
/** Translators: Variation ID */
|
/** Translators: Variation ID */
|
||||||
__( 'Variation Id: %s', 'woocommerce' ),
|
__( 'Variation Id: %s', 'woocommerce' ),
|
||||||
( selection as ProductVariation ).id
|
singleSelection?.id
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -64,14 +68,13 @@ export function VariationActions( {
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
href={ ( selection as ProductVariation ).permalink }
|
href={ singleSelection?.permalink }
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
onClick={ () => {
|
onClick={ () => {
|
||||||
recordEvent( 'product_variations_preview', {
|
recordEvent( 'product_variations_preview', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
variation_id: ( selection as ProductVariation )
|
variation_id: singleSelection?.id,
|
||||||
.id,
|
|
||||||
} );
|
} );
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import { ProductAttribute, ProductVariation } from '@woocommerce/data';
|
import {
|
||||||
|
PartialProductVariation,
|
||||||
|
ProductAttribute,
|
||||||
|
ProductVariation,
|
||||||
|
} from '@woocommerce/data';
|
||||||
|
|
||||||
export type VariationsTableRowProps = {
|
export type VariationsTableRowProps = {
|
||||||
variation: ProductVariation;
|
variation: ProductVariation;
|
||||||
|
@ -11,8 +15,8 @@ export type VariationsTableRowProps = {
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
isSelectionDisabled?: boolean;
|
isSelectionDisabled?: boolean;
|
||||||
hideActionButtons?: boolean;
|
hideActionButtons?: boolean;
|
||||||
onChange( variation: ProductVariation ): void;
|
onChange( variation: PartialProductVariation ): void;
|
||||||
onDelete( variation: ProductVariation ): void;
|
onDelete( variation: PartialProductVariation ): void;
|
||||||
onEdit( event: MouseEvent< HTMLAnchorElement > ): void;
|
onEdit( event: MouseEvent< HTMLAnchorElement > ): void;
|
||||||
onSelect( value: boolean ): void;
|
onSelect( value: boolean ): void;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
import { Tag, __experimentalTooltip as Tooltip } from '@woocommerce/components';
|
import { Tag, __experimentalTooltip as Tooltip } from '@woocommerce/components';
|
||||||
import { CurrencyContext } from '@woocommerce/currency';
|
import { CurrencyContext } from '@woocommerce/currency';
|
||||||
import { ProductVariation } from '@woocommerce/data';
|
import { PartialProductVariation, ProductVariation } from '@woocommerce/data';
|
||||||
import { getNewPath } from '@woocommerce/navigation';
|
import { getNewPath } from '@woocommerce/navigation';
|
||||||
import { Button, CheckboxControl, Spinner } from '@wordpress/components';
|
import { Button, CheckboxControl, Spinner } from '@wordpress/components';
|
||||||
import {
|
import {
|
||||||
|
@ -90,11 +90,12 @@ export function VariationsTableRow( {
|
||||||
[ variableAttributes, variation ]
|
[ variableAttributes, variation ]
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleChange( value: Partial< ProductVariation > ) {
|
function handleChange( values: PartialProductVariation[] ) {
|
||||||
onChange( {
|
onChange( values[ 0 ] );
|
||||||
...variation,
|
}
|
||||||
...value,
|
|
||||||
} );
|
function handleDelete( values: PartialProductVariation[] ) {
|
||||||
|
onDelete( values[ 0 ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -241,9 +242,9 @@ export function VariationsTableRow( {
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<SingleUpdateMenu
|
<SingleUpdateMenu
|
||||||
selection={ variation }
|
selection={ [ variation ] }
|
||||||
onChange={ handleChange }
|
onChange={ handleChange }
|
||||||
onDelete={ onDelete }
|
onDelete={ handleDelete }
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) }
|
) }
|
||||||
|
|
|
@ -3,7 +3,11 @@
|
||||||
*/
|
*/
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { Button, CheckboxControl, Notice } from '@wordpress/components';
|
import { Button, CheckboxControl, Notice } from '@wordpress/components';
|
||||||
import { Product, ProductVariation } from '@woocommerce/data';
|
import {
|
||||||
|
PartialProductVariation,
|
||||||
|
Product,
|
||||||
|
ProductVariation,
|
||||||
|
} from '@woocommerce/data';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
import { ListItem, Sortable } from '@woocommerce/components';
|
import { ListItem, Sortable } from '@woocommerce/components';
|
||||||
import {
|
import {
|
||||||
|
@ -37,10 +41,8 @@ type VariationsTableProps = {
|
||||||
noticeActions?: {
|
noticeActions?: {
|
||||||
label: string;
|
label: string;
|
||||||
onClick: (
|
onClick: (
|
||||||
handleUpdateAll: ( values: Partial< ProductVariation >[] ) => void,
|
handleUpdateAll: ( values: PartialProductVariation[] ) => void,
|
||||||
handleDeleteAll: (
|
handleDeleteAll: ( values: PartialProductVariation[] ) => void
|
||||||
values: Pick< ProductVariation, 'id' >[]
|
|
||||||
) => void
|
|
||||||
) => void;
|
) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
variant?: string;
|
variant?: string;
|
||||||
|
@ -174,7 +176,7 @@ export const VariationsTable = forwardRef<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDeleteVariationClick( variation: ProductVariation ) {
|
function handleDeleteVariationClick( variation: PartialProductVariation ) {
|
||||||
onDelete( variation.id )
|
onDelete( variation.id )
|
||||||
.then( ( response ) => {
|
.then( ( response ) => {
|
||||||
recordEvent( 'product_variations_delete', {
|
recordEvent( 'product_variations_delete', {
|
||||||
|
@ -194,7 +196,7 @@ export const VariationsTable = forwardRef<
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleVariationChange( variation: Partial< ProductVariation > ) {
|
function handleVariationChange( variation: PartialProductVariation ) {
|
||||||
onUpdate( variation )
|
onUpdate( variation )
|
||||||
.then( ( response ) => {
|
.then( ( response ) => {
|
||||||
recordEvent( 'product_variations_change', {
|
recordEvent( 'product_variations_change', {
|
||||||
|
@ -214,7 +216,7 @@ export const VariationsTable = forwardRef<
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUpdateAll( values: Partial< ProductVariation >[] ) {
|
function handleUpdateAll( values: PartialProductVariation[] ) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
||||||
onBatchUpdate( values )
|
onBatchUpdate( values )
|
||||||
|
@ -235,10 +237,10 @@ export const VariationsTable = forwardRef<
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDeleteAll( values: Partial< ProductVariation >[] ) {
|
function handleDeleteAll( values: PartialProductVariation[] ) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
||||||
onBatchDelete( values.map( ( variation ) => variation.id ) )
|
onBatchDelete( values )
|
||||||
.then( ( response: VariationResponseProps ) => {
|
.then( ( response: VariationResponseProps ) => {
|
||||||
recordEvent( 'product_variations_delete_all', {
|
recordEvent( 'product_variations_delete_all', {
|
||||||
source: TRACKS_SOURCE,
|
source: TRACKS_SOURCE,
|
||||||
|
|
Loading…
Reference in New Issue