124 lines
3.1 KiB
JavaScript
124 lines
3.1 KiB
JavaScript
|
/**
|
||
|
* External dependencies
|
||
|
*/
|
||
|
import { useState, useEffect } from '@wordpress/element';
|
||
|
import { getAttributes, getTerms } from '@woocommerce/editor-components/utils';
|
||
|
|
||
|
/**
|
||
|
* Internal dependencies
|
||
|
*/
|
||
|
import { formatError } from '../base/utils/errors.js';
|
||
|
|
||
|
/**
|
||
|
* Get attribute data (name, taxonomy etc) from server data.
|
||
|
*
|
||
|
* @param {number} attributeId Attribute ID to look for.
|
||
|
* @param {Array|null} attributeList List of attributes.
|
||
|
* @param {string} matchField Field to match on. e.g. id or slug.
|
||
|
*/
|
||
|
const getAttributeData = ( attributeId, attributeList, matchField = 'id' ) => {
|
||
|
return Array.isArray( attributeList )
|
||
|
? attributeList.find( ( attr ) => attr[ matchField ] === attributeId )
|
||
|
: null;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* HOC that calls the useAttributes hook.
|
||
|
*
|
||
|
* @param {Function} OriginalComponent Component being wrapped.
|
||
|
*/
|
||
|
const withAttributes = ( OriginalComponent ) => {
|
||
|
return ( props ) => {
|
||
|
const { selected = [] } = props;
|
||
|
const selectedSlug = selected.length ? selected[ 0 ].attr_slug : null;
|
||
|
const [ attributes, setAttributes ] = useState( null );
|
||
|
const [ expandedAttribute, setExpandedAttribute ] = useState( 0 );
|
||
|
const [ termsList, setTermsList ] = useState( {} );
|
||
|
const [ loading, setLoading ] = useState( true );
|
||
|
const [ termsLoading, setTermsLoading ] = useState( false );
|
||
|
const [ error, setError ] = useState( null );
|
||
|
|
||
|
useEffect( () => {
|
||
|
if ( attributes === null ) {
|
||
|
getAttributes()
|
||
|
.then( ( newAttributes ) => {
|
||
|
newAttributes = newAttributes.map( ( attribute ) => ( {
|
||
|
...attribute,
|
||
|
parent: 0,
|
||
|
} ) );
|
||
|
|
||
|
setAttributes( newAttributes );
|
||
|
|
||
|
if ( selectedSlug ) {
|
||
|
const selectedAttributeFromTerm = getAttributeData(
|
||
|
selectedSlug,
|
||
|
newAttributes,
|
||
|
'taxonomy'
|
||
|
);
|
||
|
|
||
|
if ( selectedAttributeFromTerm ) {
|
||
|
setExpandedAttribute(
|
||
|
selectedAttributeFromTerm.id
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
} )
|
||
|
.catch( async ( e ) => {
|
||
|
setError( await formatError( e ) );
|
||
|
} )
|
||
|
.finally( () => {
|
||
|
setLoading( false );
|
||
|
} );
|
||
|
}
|
||
|
}, [ attributes, selectedSlug ] );
|
||
|
|
||
|
useEffect( () => {
|
||
|
const attributeData = getAttributeData(
|
||
|
expandedAttribute,
|
||
|
attributes
|
||
|
);
|
||
|
|
||
|
if ( ! attributeData ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
setTermsLoading( true );
|
||
|
|
||
|
getTerms( expandedAttribute )
|
||
|
.then( ( newTerms ) => {
|
||
|
newTerms = newTerms.map( ( term ) => ( {
|
||
|
...term,
|
||
|
parent: expandedAttribute,
|
||
|
attr_slug: attributeData.taxonomy,
|
||
|
} ) );
|
||
|
|
||
|
setTermsList( ( previousTermsList ) => ( {
|
||
|
...previousTermsList,
|
||
|
[ expandedAttribute ]: newTerms,
|
||
|
} ) );
|
||
|
} )
|
||
|
.catch( async ( e ) => {
|
||
|
setError( await formatError( e ) );
|
||
|
} )
|
||
|
.finally( () => {
|
||
|
setTermsLoading( false );
|
||
|
} );
|
||
|
}, [ expandedAttribute, attributes ] );
|
||
|
|
||
|
return (
|
||
|
<OriginalComponent
|
||
|
{ ...props }
|
||
|
attributes={ attributes || [] }
|
||
|
error={ error }
|
||
|
expandedAttribute={ expandedAttribute }
|
||
|
onExpandAttribute={ setExpandedAttribute }
|
||
|
isLoading={ loading }
|
||
|
termsAreLoading={ termsLoading }
|
||
|
termsList={ termsList }
|
||
|
/>
|
||
|
);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
export default withAttributes;
|