initial commit

This commit is contained in:
2021-12-10 12:03:04 +00:00
commit c46c7ddbf0
3643 changed files with 582794 additions and 0 deletions

View File

@ -0,0 +1,82 @@
/**
* External dependencies
*/
import { sortBy } from 'lodash';
/**
* Given a query object, removes an attribute filter by a single slug.
*
* @param {Array} query Current query object.
* @param {Function} setQuery Callback to update the current query object.
* @param {Object} attribute An attribute object.
* @param {string} slug Term slug to remove.
*/
export const removeAttributeFilterBySlug = (
query = [],
setQuery = () => {},
attribute,
slug = ''
) => {
// Get current filter for provided attribute.
const foundQuery = query.filter(
( item ) => item.attribute === attribute.taxonomy
);
const currentQuery = foundQuery.length ? foundQuery[ 0 ] : null;
if (
! currentQuery ||
! currentQuery.slug ||
! Array.isArray( currentQuery.slug ) ||
! currentQuery.slug.includes( slug )
) {
return;
}
const newSlugs = currentQuery.slug.filter( ( item ) => item !== slug );
// Remove current attribute filter from query.
const returnQuery = query.filter(
( item ) => item.attribute !== attribute.taxonomy
);
// Add a new query for selected terms, if provided.
if ( newSlugs.length > 0 ) {
currentQuery.slug = newSlugs.sort();
returnQuery.push( currentQuery );
}
setQuery( sortBy( returnQuery, 'attribute' ) );
};
/**
* Given a query object, sets the query up to filter by a given attribute and attribute terms.
*
* @param {Array} query Current query object.
* @param {Function} setQuery Callback to update the current query object.
* @param {Object} attribute An attribute object.
* @param {Array} attributeTerms Array of term objects.
* @param {string} operator Operator for the filter. Valid values: in, and.
*/
export const updateAttributeFilter = (
query = [],
setQuery = () => {},
attribute,
attributeTerms = [],
operator = 'in'
) => {
const returnQuery = query.filter(
( item ) => item.attribute !== attribute.taxonomy
);
if ( attributeTerms.length === 0 ) {
setQuery( returnQuery );
} else {
returnQuery.push( {
attribute: attribute.taxonomy,
operator,
slug: attributeTerms.map( ( { slug } ) => slug ).sort(),
} );
setQuery( sortBy( returnQuery, 'attribute' ) );
}
};

View File

@ -0,0 +1,80 @@
/**
* External dependencies
*/
import { getSetting } from '@woocommerce/settings';
const ATTRIBUTES = getSetting( 'attributes', [] );
/**
* Format an attribute from the settings into an object with standardized keys.
*
* @param {Object} attribute The attribute object.
*/
const attributeSettingToObject = ( attribute ) => {
if ( ! attribute || ! attribute.attribute_name ) {
return null;
}
return {
id: parseInt( attribute.attribute_id, 10 ),
name: attribute.attribute_name,
taxonomy: 'pa_' + attribute.attribute_name,
label: attribute.attribute_label,
};
};
/**
* Format all attribute settings into objects.
*/
const attributeObjects = ATTRIBUTES.reduce( ( acc, current ) => {
const attributeObject = attributeSettingToObject( current );
if ( attributeObject.id ) {
acc.push( attributeObject );
}
return acc;
}, [] );
/**
* Get attribute data by taxonomy.
*
* @param {number} attributeId The attribute ID.
* @return {Object|undefined} The attribute object if it exists.
*/
export const getAttributeFromID = ( attributeId ) => {
if ( ! attributeId ) {
return;
}
return attributeObjects.find( ( attribute ) => {
return attribute.id === attributeId;
} );
};
/**
* Get attribute data by taxonomy.
*
* @param {string} taxonomy The attribute taxonomy name e.g. pa_color.
* @return {Object|undefined} The attribute object if it exists.
*/
export const getAttributeFromTaxonomy = ( taxonomy ) => {
if ( ! taxonomy ) {
return;
}
return attributeObjects.find( ( attribute ) => {
return attribute.taxonomy === taxonomy;
} );
};
/**
* Get the taxonomy of an attribute by Attribute ID.
*
* @param {number} attributeId The attribute ID.
* @return {string} The taxonomy name.
*/
export const getTaxonomyFromAttributeId = ( attributeId ) => {
if ( ! attributeId ) {
return null;
}
const attribute = getAttributeFromID( attributeId );
return attribute ? attribute.taxonomy : null;
};

View File

@ -0,0 +1,29 @@
/**
* Get the src of the first image attached to a product (the featured image).
*
* @param {Object} product The product object to get the images from.
* @param {Array} product.images The array of images, destructured from the product object.
* @return {string} The full URL to the image.
*/
export function getImageSrcFromProduct( product ) {
if ( ! product || ! product.images || ! product.images.length ) {
return '';
}
return product.images[ 0 ].src || '';
}
/**
* Get the ID of the first image attached to a product (the featured image).
*
* @param {Object} product The product object to get the images from.
* @param {Array} product.images The array of images, destructured from the product object.
* @return {number} The ID of the image.
*/
export function getImageIdFromProduct( product ) {
if ( ! product || ! product.images || ! product.images.length ) {
return 0;
}
return product.images[ 0 ].id || 0;
}

View File

@ -0,0 +1,75 @@
/**
* External dependencies
*/
import { getSetting } from '@woocommerce/settings';
export const sharedAttributeBlockTypes = [
'woocommerce/product-best-sellers',
'woocommerce/product-category',
'woocommerce/product-new',
'woocommerce/product-on-sale',
'woocommerce/product-top-rated',
];
export default {
/**
* Number of columns.
*/
columns: {
type: 'number',
default: getSetting( 'default_columns', 3 ),
},
/**
* Number of rows.
*/
rows: {
type: 'number',
default: getSetting( 'default_rows', 3 ),
},
/**
* How to align cart buttons.
*/
alignButtons: {
type: 'boolean',
default: false,
},
/**
* Product category, used to display only products in the given categories.
*/
categories: {
type: 'array',
default: [],
},
/**
* Product category operator, used to restrict to products in all or any selected categories.
*/
catOperator: {
type: 'string',
default: 'any',
},
/**
* Content visibility setting
*/
contentVisibility: {
type: 'object',
default: {
title: true,
price: true,
rating: true,
button: true,
},
},
/**
* Are we previewing?
*/
isPreview: {
type: 'boolean',
default: false,
},
};

View File

@ -0,0 +1,84 @@
/**
* Internal dependencies
*/
import { getImageSrcFromProduct, getImageIdFromProduct } from '../products';
describe( 'getImageSrcFromProduct', () => {
test( 'returns first image src', () => {
const imageSrc = getImageSrcFromProduct( {
images: [ { src: 'foo.jpg' } ],
} );
expect( imageSrc ).toBe( 'foo.jpg' );
} );
test( 'returns empty string if no product was provided', () => {
const imageSrc = getImageSrcFromProduct();
expect( imageSrc ).toBe( '' );
} );
test( 'returns empty string if product is empty', () => {
const imageSrc = getImageSrcFromProduct( {} );
expect( imageSrc ).toBe( '' );
} );
test( 'returns empty string if product has no images', () => {
const imageSrc = getImageSrcFromProduct( { images: null } );
expect( imageSrc ).toBe( '' );
} );
test( 'returns empty string if product has 0 images', () => {
const imageSrc = getImageSrcFromProduct( { images: [] } );
expect( imageSrc ).toBe( '' );
} );
test( 'returns empty string if product image has no src attribute', () => {
const imageSrc = getImageSrcFromProduct( { images: [ {} ] } );
expect( imageSrc ).toBe( '' );
} );
} );
describe( 'getImageIdFromProduct', () => {
test( 'returns first image id', () => {
const imageUrl = getImageIdFromProduct( {
images: [ { id: 123 } ],
} );
expect( imageUrl ).toBe( 123 );
} );
test( 'returns 0 if no product was provided', () => {
const imageUrl = getImageIdFromProduct();
expect( imageUrl ).toBe( 0 );
} );
test( 'returns 0 if product is empty', () => {
const imageUrl = getImageIdFromProduct( {} );
expect( imageUrl ).toBe( 0 );
} );
test( 'returns 0 if product has no images', () => {
const imageUrl = getImageIdFromProduct( { images: null } );
expect( imageUrl ).toBe( 0 );
} );
test( 'returns 0 if product has 0 images', () => {
const imageUrl = getImageIdFromProduct( { images: [] } );
expect( imageUrl ).toBe( 0 );
} );
test( 'returns 0 if product image has no src attribute', () => {
const imageUrl = getImageIdFromProduct( { images: [ {} ] } );
expect( imageUrl ).toBe( 0 );
} );
} );