Add update product actions to product data store (#33282)
* Add update product actions to product data store * Add changelog entry * Use MutableProperties for update data * Omit read only properties instead of picking mutable properties
This commit is contained in:
parent
935f915cb5
commit
9d98f1b1da
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add update product actions to product data store #33282
|
|
@ -7,6 +7,8 @@ export enum TYPES {
|
|||
GET_PRODUCTS_ERROR = 'GET_PRODUCTS_ERROR',
|
||||
GET_PRODUCTS_TOTAL_COUNT_SUCCESS = 'GET_PRODUCTS_TOTAL_COUNT_SUCCESS',
|
||||
GET_PRODUCTS_TOTAL_COUNT_ERROR = 'GET_PRODUCTS_TOTAL_COUNT_ERROR',
|
||||
UPDATE_PRODUCT_ERROR = 'UPDATE_PRODUCT_ERROR',
|
||||
UPDATE_PRODUCT_SUCCESS = 'UPDATE_PRODUCT_SUCCESS',
|
||||
}
|
||||
|
||||
export default TYPES;
|
||||
|
|
|
@ -9,7 +9,7 @@ import { DispatchFromMap } from '@automattic/data-stores';
|
|||
*/
|
||||
import TYPES from './action-types';
|
||||
import {
|
||||
MutableProperties,
|
||||
ReadOnlyProperties,
|
||||
PartialProduct,
|
||||
Product,
|
||||
ProductQuery,
|
||||
|
@ -35,7 +35,7 @@ export function getProductError(
|
|||
};
|
||||
}
|
||||
|
||||
function createProductSuccess( id: number, product: PartialProduct ) {
|
||||
function createProductSuccess( id: number, product: Partial< Product > ) {
|
||||
return {
|
||||
type: TYPES.CREATE_PRODUCT_SUCCESS as const,
|
||||
id,
|
||||
|
@ -54,6 +54,22 @@ export function createProductError(
|
|||
};
|
||||
}
|
||||
|
||||
function updateProductSuccess( id: number, product: Partial< Product > ) {
|
||||
return {
|
||||
type: TYPES.UPDATE_PRODUCT_SUCCESS as const,
|
||||
id,
|
||||
product,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateProductError( id: number, error: unknown ) {
|
||||
return {
|
||||
type: TYPES.UPDATE_PRODUCT_ERROR as const,
|
||||
id,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function getProductsSuccess(
|
||||
query: Partial< ProductQuery >,
|
||||
products: PartialProduct[],
|
||||
|
@ -100,7 +116,7 @@ export function getProductsTotalCountError(
|
|||
};
|
||||
}
|
||||
|
||||
export function* createProduct( data: Pick< Product, MutableProperties > ) {
|
||||
export function* createProduct( data: Omit< Product, ReadOnlyProperties > ) {
|
||||
try {
|
||||
const product: Product = yield apiFetch( {
|
||||
path: WC_PRODUCT_NAMESPACE,
|
||||
|
@ -116,6 +132,25 @@ export function* createProduct( data: Pick< Product, MutableProperties > ) {
|
|||
}
|
||||
}
|
||||
|
||||
export function* updateProduct(
|
||||
id: number,
|
||||
data: Omit< Product, ReadOnlyProperties >
|
||||
) {
|
||||
try {
|
||||
const product: Product = yield apiFetch( {
|
||||
path: `${ WC_PRODUCT_NAMESPACE }/${ id }`,
|
||||
method: 'PUT',
|
||||
data,
|
||||
} );
|
||||
|
||||
yield updateProductSuccess( product.id, product );
|
||||
return product;
|
||||
} catch ( error ) {
|
||||
yield updateProductError( id, error );
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export type Actions = ReturnType<
|
||||
| typeof createProductError
|
||||
| typeof createProductSuccess
|
||||
|
@ -125,8 +160,11 @@ export type Actions = ReturnType<
|
|||
| typeof getProductsError
|
||||
| typeof getProductsTotalCountSuccess
|
||||
| typeof getProductsTotalCountError
|
||||
| typeof updateProductError
|
||||
| typeof updateProductSuccess
|
||||
>;
|
||||
|
||||
export type ActionDispatchers = DispatchFromMap< {
|
||||
createProduct: typeof createProduct;
|
||||
updateProduct: typeof updateProduct;
|
||||
} >;
|
||||
|
|
|
@ -39,6 +39,7 @@ const reducer: Reducer< ProductState, Actions > = (
|
|||
switch ( payload.type ) {
|
||||
case TYPES.CREATE_PRODUCT_SUCCESS:
|
||||
case TYPES.GET_PRODUCT_SUCCESS:
|
||||
case TYPES.UPDATE_PRODUCT_SUCCESS:
|
||||
const productData = state.data || {};
|
||||
return {
|
||||
...state,
|
||||
|
@ -99,6 +100,14 @@ const reducer: Reducer< ProductState, Actions > = (
|
|||
) ]: payload.error,
|
||||
},
|
||||
};
|
||||
case TYPES.UPDATE_PRODUCT_ERROR:
|
||||
return {
|
||||
...state,
|
||||
errors: {
|
||||
...state.errors,
|
||||
[ `update/${ payload.id }` ]: payload.error,
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -85,6 +85,15 @@ export const getCreateProductError = (
|
|||
return state.errors[ resourceName ];
|
||||
};
|
||||
|
||||
export const getUpdateProductError = (
|
||||
state: ProductState,
|
||||
id: number,
|
||||
query: ProductQuery
|
||||
) => {
|
||||
const resourceName = getProductResourceName( query );
|
||||
return state.errors[ `update/${ id }/${ resourceName }` ];
|
||||
};
|
||||
|
||||
export type ProductsSelectors = {
|
||||
getCreateProductError: WPDataSelector< typeof getCreateProductError >;
|
||||
getProducts: WPDataSelector< typeof getProducts >;
|
||||
|
|
|
@ -210,4 +210,54 @@ describe( 'products reducer', () => {
|
|||
|
||||
expect( state.errors[ resourceName ] ).toBe( error );
|
||||
} );
|
||||
|
||||
it( 'should handle UPDATE_PRODUCT_SUCCESS', () => {
|
||||
const itemType = 'guyisms';
|
||||
const initialState: ProductState = {
|
||||
products: {
|
||||
[ itemType ]: {
|
||||
data: [ 1, 2 ],
|
||||
},
|
||||
},
|
||||
productsCount: {
|
||||
'total-guyisms:{}': 2,
|
||||
},
|
||||
errors: {},
|
||||
data: {
|
||||
1: { id: 1, name: 'Donkey', status: 'draft' },
|
||||
2: { id: 2, name: 'Sauce', status: 'publish' },
|
||||
},
|
||||
};
|
||||
const product: PartialProduct = {
|
||||
id: 2,
|
||||
name: 'Holy smokes!',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const state = reducer( initialState, {
|
||||
type: TYPES.UPDATE_PRODUCT_SUCCESS,
|
||||
id: product.id,
|
||||
product,
|
||||
} );
|
||||
|
||||
expect( state.products ).toEqual( initialState.products );
|
||||
expect( state.errors ).toEqual( initialState.errors );
|
||||
|
||||
expect( state.data[ 1 ] ).toEqual( initialState.data[ 1 ] );
|
||||
expect( state.data[ 2 ].id ).toEqual( initialState.data[ 2 ].id );
|
||||
expect( state.data[ 2 ].title ).toEqual( initialState.data[ 2 ].title );
|
||||
expect( state.data[ 2 ].name ).toEqual( product.name );
|
||||
} );
|
||||
|
||||
it( 'should handle UPDATE_PRODUCT_ERROR', () => {
|
||||
const id = 1;
|
||||
const error = 'Baaam!';
|
||||
const state = reducer( defaultState, {
|
||||
type: TYPES.UPDATE_PRODUCT_ERROR,
|
||||
id,
|
||||
error,
|
||||
} );
|
||||
|
||||
expect( state.errors[ `update/${ id }` ] ).toBe( error );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -40,17 +40,27 @@ export type Product<
|
|||
sale_price: string;
|
||||
};
|
||||
|
||||
export type MutableProperties =
|
||||
| 'name'
|
||||
| 'slug'
|
||||
| 'type'
|
||||
| 'status'
|
||||
| 'featured'
|
||||
| 'description'
|
||||
| 'short_description'
|
||||
| 'sku'
|
||||
| 'regular_price'
|
||||
| 'sale_price';
|
||||
export type ReadOnlyProperties =
|
||||
| 'id'
|
||||
| 'permalink'
|
||||
| 'date_created'
|
||||
| 'date_created_gmt'
|
||||
| 'date_modified'
|
||||
| 'date_modified_gmt'
|
||||
| 'price'
|
||||
| 'price_html'
|
||||
| 'on_sale'
|
||||
| 'purchasable'
|
||||
| 'total_sales'
|
||||
| 'backorders_allowed'
|
||||
| 'backordered'
|
||||
| 'shipping_required'
|
||||
| 'shipping_taxable'
|
||||
| 'shipping_class_id'
|
||||
| 'average_rating'
|
||||
| 'rating_count'
|
||||
| 'related_ids'
|
||||
| 'variations';
|
||||
|
||||
export type PartialProduct = Partial< Product > & Pick< Product, 'id' >;
|
||||
|
||||
|
|
Loading…
Reference in New Issue