Request tags only when we need them (#47068)
* Get Tags conditionally * Create file types.ts * Add changelog * Fix tests
This commit is contained in:
parent
b7e30ea5b3
commit
e5e78a33bf
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: dev
|
||||||
|
|
||||||
|
Request tags only when we need them #47068
|
|
@ -19,7 +19,7 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"usesContext": [ "postType" ],
|
"usesContext": [ "postType", "isInSelectedTab" ],
|
||||||
"supports": {
|
"supports": {
|
||||||
"align": false,
|
"align": false,
|
||||||
"html": false,
|
"html": false,
|
||||||
|
|
|
@ -21,13 +21,13 @@ import { ProductEditorBlockEditProps } from '../../../types';
|
||||||
|
|
||||||
export function Edit( {
|
export function Edit( {
|
||||||
attributes,
|
attributes,
|
||||||
context,
|
context: { postType, isInSelectedTab },
|
||||||
}: ProductEditorBlockEditProps< BlockAttributes > ) {
|
}: ProductEditorBlockEditProps< BlockAttributes > ) {
|
||||||
const blockProps = useWooBlockProps( attributes );
|
const blockProps = useWooBlockProps( attributes );
|
||||||
const { name, label, placeholder } = attributes;
|
const { name, label, placeholder } = attributes;
|
||||||
const [ tags, setTags ] = useEntityProp<
|
const [ tags, setTags ] = useEntityProp<
|
||||||
Pick< ProductTag, 'id' | 'name' >[]
|
Pick< ProductTag, 'id' | 'name' >[]
|
||||||
>( 'postType', context.postType || 'product', name || 'tags' );
|
>( 'postType', postType || 'product', name || 'tags' );
|
||||||
|
|
||||||
const tagFieldId = useInstanceId( BaseControl, 'tag-field' ) as string;
|
const tagFieldId = useInstanceId( BaseControl, 'tag-field' ) as string;
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ export function Edit( {
|
||||||
{
|
{
|
||||||
<TagField
|
<TagField
|
||||||
id={ tagFieldId }
|
id={ tagFieldId }
|
||||||
|
isVisible={ isInSelectedTab }
|
||||||
label={ label || __( 'Tags', 'woocommerce' ) }
|
label={ label || __( 'Tags', 'woocommerce' ) }
|
||||||
placeholder={
|
placeholder={
|
||||||
placeholder ||
|
placeholder ||
|
||||||
|
|
|
@ -15,12 +15,7 @@ import {
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { TRACKS_SOURCE } from '../../constants';
|
import { TRACKS_SOURCE } from '../../constants';
|
||||||
|
import { CreateTagModalProps } from './types';
|
||||||
type CreateTagModalProps = {
|
|
||||||
initialTagName?: string;
|
|
||||||
onCancel: () => void;
|
|
||||||
onCreate: ( newTag: ProductTag ) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CreateTagModal: React.FC< CreateTagModalProps > = ( {
|
export const CreateTagModal: React.FC< CreateTagModalProps > = ( {
|
||||||
initialTagName,
|
initialTagName,
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { useState, createElement, Fragment } from '@wordpress/element';
|
import {
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
createElement,
|
||||||
|
Fragment,
|
||||||
|
} from '@wordpress/element';
|
||||||
import {
|
import {
|
||||||
TreeItemType,
|
TreeItemType,
|
||||||
__experimentalSelectTreeControl as SelectTree,
|
__experimentalSelectTreeControl as SelectTree,
|
||||||
|
@ -18,26 +23,19 @@ import { useDebounce } from '@wordpress/compose';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { useTagSearch, ProductTagNode } from './use-tag-search';
|
import { useTagSearch } from './use-tag-search';
|
||||||
import { TRACKS_SOURCE } from '../../constants';
|
import { TRACKS_SOURCE } from '../../constants';
|
||||||
import { CreateTagModal } from './create-tag-modal';
|
import { CreateTagModal } from './create-tag-modal';
|
||||||
|
import { ProductTagNodeProps, TagFieldProps } from './types';
|
||||||
|
|
||||||
type TagFieldProps = {
|
export function mapFromTagToTreeItem( val: ProductTagNodeProps ): TreeItemType {
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
placeholder: string;
|
|
||||||
value?: ProductTagNode[];
|
|
||||||
onChange: ( value: ProductTagNode[] ) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function mapFromTagToTreeItem( val: ProductTagNode ): TreeItemType {
|
|
||||||
return {
|
return {
|
||||||
value: String( val.id ),
|
value: String( val.id ),
|
||||||
label: val.name,
|
label: val.name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapFromTreeItemToTag( val: TreeItemType ): ProductTagNode {
|
export function mapFromTreeItemToTag( val: TreeItemType ): ProductTagNodeProps {
|
||||||
return {
|
return {
|
||||||
id: +val.value,
|
id: +val.value,
|
||||||
name: val.label,
|
name: val.label,
|
||||||
|
@ -45,19 +43,20 @@ export function mapFromTreeItemToTag( val: TreeItemType ): ProductTagNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapFromTagsToTreeItems(
|
export function mapFromTagsToTreeItems(
|
||||||
tags: ProductTagNode[]
|
tags: ProductTagNodeProps[]
|
||||||
): TreeItemType[] {
|
): TreeItemType[] {
|
||||||
return tags.map( mapFromTagToTreeItem );
|
return tags.map( mapFromTagToTreeItem );
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapFromTreeItemsToTags(
|
export function mapFromTreeItemsToTags(
|
||||||
tags: TreeItemType[]
|
tags: TreeItemType[]
|
||||||
): ProductTagNode[] {
|
): ProductTagNodeProps[] {
|
||||||
return tags.map( mapFromTreeItemToTag );
|
return tags.map( mapFromTreeItemToTag );
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TagField: React.FC< TagFieldProps > = ( {
|
export const TagField: React.FC< TagFieldProps > = ( {
|
||||||
id,
|
id,
|
||||||
|
isVisible = false,
|
||||||
label,
|
label,
|
||||||
placeholder,
|
placeholder,
|
||||||
value = [],
|
value = [],
|
||||||
|
@ -80,6 +79,12 @@ export const TagField: React.FC< TagFieldProps > = ( {
|
||||||
setNewInputValue( searchString );
|
setNewInputValue( searchString );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
if ( isVisible ) {
|
||||||
|
searchTags();
|
||||||
|
}
|
||||||
|
}, [ isVisible ] );
|
||||||
|
|
||||||
const searchDelayed = useDebounce( onInputChange, 150 );
|
const searchDelayed = useDebounce( onInputChange, 150 );
|
||||||
|
|
||||||
const onSave = async () => {
|
const onSave = async () => {
|
||||||
|
@ -132,7 +137,7 @@ export const TagField: React.FC< TagFieldProps > = ( {
|
||||||
selected={ mapFromTagsToTreeItems( value ) }
|
selected={ mapFromTagsToTreeItems( value ) }
|
||||||
onSelect={ ( selectedItems ) => {
|
onSelect={ ( selectedItems ) => {
|
||||||
if ( Array.isArray( selectedItems ) ) {
|
if ( Array.isArray( selectedItems ) ) {
|
||||||
const newItems: ProductTagNode[] =
|
const newItems: ProductTagNodeProps[] =
|
||||||
mapFromTreeItemsToTags(
|
mapFromTreeItemsToTags(
|
||||||
selectedItems.filter(
|
selectedItems.filter(
|
||||||
( { value: selectedItemValue } ) =>
|
( { value: selectedItemValue } ) =>
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { createElement } from '@wordpress/element';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { TagField } from '../tag-field';
|
import { TagField } from '../tag-field';
|
||||||
import { ProductTagNode } from '../use-tag-search';
|
import { ProductTagNodeProps } from '../types';
|
||||||
|
|
||||||
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
|
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
|
||||||
|
|
||||||
|
@ -37,9 +37,10 @@ describe( 'TagField', () => {
|
||||||
{ ( { getInputProps }: FormContextType< Product > ) => (
|
{ ( { getInputProps }: FormContextType< Product > ) => (
|
||||||
<TagField
|
<TagField
|
||||||
id="tag-field"
|
id="tag-field"
|
||||||
|
isVisible={ true }
|
||||||
label="Tags"
|
label="Tags"
|
||||||
placeholder="Search or create tag…"
|
placeholder="Search or create tag…"
|
||||||
{ ...getInputProps< ProductTagNode[] >( 'tags' ) }
|
{ ...getInputProps< ProductTagNodeProps[] >( 'tags' ) }
|
||||||
/>
|
/>
|
||||||
) }
|
) }
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -61,9 +62,10 @@ describe( 'TagField', () => {
|
||||||
{ ( { getInputProps }: FormContextType< Product > ) => (
|
{ ( { getInputProps }: FormContextType< Product > ) => (
|
||||||
<TagField
|
<TagField
|
||||||
id="another-tag-field"
|
id="another-tag-field"
|
||||||
|
isVisible={ true }
|
||||||
label="Tags"
|
label="Tags"
|
||||||
placeholder="Search or create tag…"
|
placeholder="Search or create tag…"
|
||||||
{ ...getInputProps< ProductTagNode[] >( 'tags' ) }
|
{ ...getInputProps< ProductTagNodeProps[] >( 'tags' ) }
|
||||||
/>
|
/>
|
||||||
) }
|
) }
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { ProductTag } from '@woocommerce/data';
|
||||||
|
|
||||||
|
export type CreateTagModalProps = {
|
||||||
|
initialTagName?: string;
|
||||||
|
onCancel: () => void;
|
||||||
|
onCreate: ( newTag: ProductTag ) => void;
|
||||||
|
};
|
||||||
|
export type ProductTagNodeProps = Pick< ProductTag, 'id' | 'name' >;
|
||||||
|
export type TagFieldProps = {
|
||||||
|
id: string;
|
||||||
|
isVisible?: boolean;
|
||||||
|
label: string;
|
||||||
|
placeholder: string;
|
||||||
|
value?: ProductTagNodeProps[];
|
||||||
|
onChange: ( value: ProductTagNodeProps[] ) => void;
|
||||||
|
};
|
|
@ -1,15 +1,13 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { useEffect, useState } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
import { resolveSelect } from '@wordpress/data';
|
import { resolveSelect } from '@wordpress/data';
|
||||||
import {
|
import {
|
||||||
EXPERIMENTAL_PRODUCT_TAGS_STORE_NAME,
|
EXPERIMENTAL_PRODUCT_TAGS_STORE_NAME,
|
||||||
ProductTag,
|
ProductTag,
|
||||||
} from '@woocommerce/data';
|
} from '@woocommerce/data';
|
||||||
|
|
||||||
export type ProductTagNode = Pick< ProductTag, 'id' | 'name' >;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hook used to handle all the search logic for the tag search component.
|
* A hook used to handle all the search logic for the tag search component.
|
||||||
*/
|
*/
|
||||||
|
@ -30,8 +28,6 @@ export const useTagSearch = () => {
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect( fetchProductTags, [] );
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
searchTags: fetchProductTags,
|
searchTags: fetchProductTags,
|
||||||
tagsSelectList: fetchedTags,
|
tagsSelectList: fetchedTags,
|
||||||
|
|
Loading…
Reference in New Issue