AdvancedFilters: Update Search usage to use 'getLabels' from config
This commit is contained in:
parent
e766a37e58
commit
842c23201e
|
@ -4,6 +4,11 @@
|
|||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { getProductLabelsById } from 'analytics/report/products/config';
|
||||
|
||||
export const filters = [
|
||||
{ label: __( 'All Orders', 'wc-admin' ), value: 'all' },
|
||||
{
|
||||
|
@ -55,6 +60,7 @@ export const advancedFilterConfig = {
|
|||
input: {
|
||||
component: 'Search',
|
||||
type: 'products',
|
||||
getLabels: getProductLabelsById,
|
||||
},
|
||||
},
|
||||
code: {
|
|
@ -13,7 +13,7 @@ import { partial } from 'lodash';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { Card, ReportFilters } from '@woocommerce/components';
|
||||
import { filters, advancedFilterConfig } from './constants';
|
||||
import { filters, advancedFilterConfig } from './config';
|
||||
import './style.scss';
|
||||
|
||||
class OrdersReport extends Component {
|
||||
|
|
|
@ -9,6 +9,31 @@ import apiFetch from '@wordpress/api-fetch';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { stringifyQuery } from 'lib/nav-utils';
|
||||
import { NAMESPACE } from 'store/constants';
|
||||
|
||||
export const getProductLabelsById = queryString => {
|
||||
const idList = queryString
|
||||
.split( ',' )
|
||||
.map( id => parseInt( id, 10 ) )
|
||||
.filter( Boolean );
|
||||
const payload = stringifyQuery( {
|
||||
include: idList.join( ',' ),
|
||||
per_page: idList.length,
|
||||
} );
|
||||
return apiFetch( { path: NAMESPACE + 'products' + payload } );
|
||||
};
|
||||
|
||||
export const getCategoryLabelsById = queryString => {
|
||||
const idList = queryString
|
||||
.split( ',' )
|
||||
.map( id => parseInt( id, 10 ) )
|
||||
.filter( Boolean );
|
||||
const payload = stringifyQuery( {
|
||||
include: idList.join( ',' ),
|
||||
per_page: idList.length,
|
||||
} );
|
||||
return apiFetch( { path: NAMESPACE + 'products/categories' + payload } );
|
||||
};
|
||||
|
||||
export const filters = [
|
||||
{ label: __( 'All Products', 'wc-admin' ), value: 'all' },
|
||||
|
@ -29,17 +54,7 @@ export const filters = [
|
|||
settings: {
|
||||
type: 'products',
|
||||
param: 'product',
|
||||
getLabels: function( queryString ) {
|
||||
const idList = queryString
|
||||
.split( ',' )
|
||||
.map( id => parseInt( id, 10 ) )
|
||||
.filter( Boolean );
|
||||
const payload = stringifyQuery( {
|
||||
include: idList.join( ',' ),
|
||||
per_page: idList.length,
|
||||
} );
|
||||
return apiFetch( { path: '/wc/v3/products' + payload } );
|
||||
},
|
||||
getLabels: getProductLabelsById,
|
||||
labels: {
|
||||
title: __( 'Compare Products', 'wc-admin' ),
|
||||
update: __( 'Compare', 'wc-admin' ),
|
||||
|
@ -52,17 +67,7 @@ export const filters = [
|
|||
settings: {
|
||||
type: 'product_cats',
|
||||
param: 'product_cat',
|
||||
getLabels: function( queryString ) {
|
||||
const idList = queryString
|
||||
.split( ',' )
|
||||
.map( id => parseInt( id, 10 ) )
|
||||
.filter( Boolean );
|
||||
const payload = stringifyQuery( {
|
||||
include: idList.join( ',' ),
|
||||
per_page: idList.length,
|
||||
} );
|
||||
return apiFetch( { path: '/wc/v3/products/categories' + payload } );
|
||||
},
|
||||
getLabels: getCategoryLabelsById,
|
||||
labels: {
|
||||
title: __( 'Compare Product Categories', 'wc-admin' ),
|
||||
update: __( 'Compare', 'wc-admin' ),
|
|
@ -7,7 +7,7 @@ import { Component, Fragment } from '@wordpress/element';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { filters } from './constants';
|
||||
import { filters } from './config';
|
||||
import { ReportFilters } from '@woocommerce/components';
|
||||
import './style.scss';
|
||||
|
||||
|
|
|
@ -31,11 +31,9 @@ const matches = [
|
|||
class AdvancedFilters extends Component {
|
||||
constructor( props ) {
|
||||
super( props );
|
||||
const activeFiltersFromQuery = getActiveFiltersFromQuery( props.query, props.config );
|
||||
this.state = {
|
||||
match: matches[ 0 ],
|
||||
activeFilters: activeFiltersFromQuery,
|
||||
previousFilters: activeFiltersFromQuery,
|
||||
activeFilters: getActiveFiltersFromQuery( props.query, props.config ),
|
||||
};
|
||||
|
||||
this.filterListRef = createRef();
|
||||
|
@ -107,7 +105,7 @@ class AdvancedFilters extends Component {
|
|||
newFilter.value = filterConfig.input.options[ 0 ].value;
|
||||
}
|
||||
if ( filterConfig.input && 'Search' === filterConfig.input.component ) {
|
||||
newFilter.value = [];
|
||||
newFilter.value = '';
|
||||
}
|
||||
this.setState( state => {
|
||||
return {
|
||||
|
@ -129,9 +127,8 @@ class AdvancedFilters extends Component {
|
|||
}
|
||||
|
||||
getUpdateHref( activeFilters ) {
|
||||
const { previousFilters } = this.state;
|
||||
const { path, query } = this.props;
|
||||
const updatedQuery = getQueryFromActiveFilters( activeFilters, previousFilters );
|
||||
const { path, query, config } = this.props;
|
||||
const updatedQuery = getQueryFromActiveFilters( activeFilters, query, config );
|
||||
return getNewPath( updatedQuery, path, query );
|
||||
}
|
||||
|
||||
|
|
|
@ -14,27 +14,38 @@ import PropTypes from 'prop-types';
|
|||
import Search from 'components/search';
|
||||
|
||||
class SearchFilter extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
constructor( { filter, config } ) {
|
||||
super( ...arguments );
|
||||
this.onSearchChange = this.onSearchChange.bind( this );
|
||||
this.state = {
|
||||
selected: [],
|
||||
};
|
||||
|
||||
this.updateLabels = this.updateLabels.bind( this );
|
||||
|
||||
if ( filter.value.length ) {
|
||||
config.input.getLabels( filter.value ).then( this.updateLabels );
|
||||
}
|
||||
}
|
||||
|
||||
updateLabels( data ) {
|
||||
const selected = data.map( p => ( { id: p.id, label: p.name } ) );
|
||||
this.setState( { selected } );
|
||||
}
|
||||
|
||||
onSearchChange( values ) {
|
||||
this.setState( {
|
||||
selected: values,
|
||||
} );
|
||||
const { filter, onFilterChange } = this.props;
|
||||
const nextValues = values.map( value => value.id );
|
||||
onFilterChange( filter.key, 'value', nextValues );
|
||||
const idList = values.map( value => value.id ).join( ',' );
|
||||
onFilterChange( filter.key, 'value', idList );
|
||||
}
|
||||
|
||||
render() {
|
||||
const { filter, config, onFilterChange } = this.props;
|
||||
const { key, rule, value } = filter;
|
||||
const selected = value.map( id => {
|
||||
// For now
|
||||
return {
|
||||
id: parseInt( id, 10 ),
|
||||
label: id.toString(),
|
||||
};
|
||||
} );
|
||||
const { selected } = this.state;
|
||||
const { key, rule } = filter;
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="woocommerce-filters-advanced__fieldset-legend">{ config.label }</div>
|
||||
|
@ -75,7 +86,7 @@ SearchFilter.propTypes = {
|
|||
filter: PropTypes.shape( {
|
||||
key: PropTypes.string,
|
||||
rule: PropTypes.string,
|
||||
value: PropTypes.array,
|
||||
value: PropTypes.string,
|
||||
} ).isRequired,
|
||||
/**
|
||||
* Function to be called on update.
|
||||
|
|
|
@ -9,13 +9,29 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
getUrlKey,
|
||||
getSearchFilterValue,
|
||||
getActiveFiltersFromQuery,
|
||||
getUrlValue,
|
||||
getQueryFromActiveFilters,
|
||||
} from '../utils';
|
||||
import { getUrlKey, getActiveFiltersFromQuery, getQueryFromActiveFilters } from '../utils';
|
||||
|
||||
const config = {
|
||||
with_select: {
|
||||
rules: [ { value: 'is' } ],
|
||||
input: {
|
||||
component: 'SelectControl',
|
||||
options: [ { value: 'pending' } ],
|
||||
},
|
||||
},
|
||||
with_search: {
|
||||
rules: [ { value: 'includes' } ],
|
||||
input: {
|
||||
component: 'Search',
|
||||
},
|
||||
},
|
||||
with_no_rules: {
|
||||
input: {
|
||||
component: 'SelectControl',
|
||||
options: [ { value: 'pending' } ],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe( 'getUrlKey', () => {
|
||||
it( 'should return a correctly formatted string', () => {
|
||||
|
@ -29,51 +45,11 @@ describe( 'getUrlKey', () => {
|
|||
} );
|
||||
} );
|
||||
|
||||
describe( 'getSearchFilterValue', () => {
|
||||
it( 'should convert url query param into value readable by Search component', () => {
|
||||
const str = '1,2,3';
|
||||
const values = getSearchFilterValue( str );
|
||||
expect( Array.isArray( values ) ).toBeTruthy();
|
||||
expect( values[ 0 ] ).toBe( '1' );
|
||||
expect( values[ 1 ] ).toBe( '2' );
|
||||
expect( values[ 2 ] ).toBe( '3' );
|
||||
} );
|
||||
|
||||
it( 'should convert an empty string into an empty array', () => {
|
||||
const str = '';
|
||||
const values = getSearchFilterValue( str );
|
||||
expect( Array.isArray( values ) ).toBeTruthy();
|
||||
expect( values.length ).toBe( 0 );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'getActiveFiltersFromQuery', () => {
|
||||
const config = {
|
||||
with_select: {
|
||||
rules: [ { value: 'is' } ],
|
||||
input: {
|
||||
component: 'SelectControl',
|
||||
options: [ { value: 'pending' } ],
|
||||
},
|
||||
},
|
||||
with_search: {
|
||||
rules: [ { value: 'includes' } ],
|
||||
input: {
|
||||
component: 'Search',
|
||||
},
|
||||
},
|
||||
with_no_rules: {
|
||||
input: {
|
||||
component: 'SelectControl',
|
||||
options: [ { value: 'pending' } ],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it( 'should return activeFilters from a query', () => {
|
||||
const query = {
|
||||
with_select_is: 'pending',
|
||||
with_search_includes: '',
|
||||
with_search_includes: '1,2,3',
|
||||
with_no_rules: 'pending',
|
||||
};
|
||||
|
||||
|
@ -91,7 +67,7 @@ describe( 'getActiveFiltersFromQuery', () => {
|
|||
const with_search = activeFilters[ 1 ];
|
||||
expect( with_search.key ).toBe( 'with_search' );
|
||||
expect( with_search.rule ).toBe( 'includes' );
|
||||
expect( with_search.value ).toEqual( [] );
|
||||
expect( with_search.value ).toEqual( '1,2,3' );
|
||||
|
||||
// with_search
|
||||
const with_no_rules = activeFilters[ 2 ];
|
||||
|
@ -119,28 +95,6 @@ describe( 'getActiveFiltersFromQuery', () => {
|
|||
} );
|
||||
} );
|
||||
|
||||
describe( 'getUrlValue', () => {
|
||||
it( 'should pass through a string', () => {
|
||||
const value = getUrlValue( 'my string' );
|
||||
expect( value ).toBe( 'my string' );
|
||||
} );
|
||||
|
||||
it( 'should return null for a non-string value', () => {
|
||||
const value = getUrlValue( {} );
|
||||
expect( value ).toBeNull();
|
||||
} );
|
||||
|
||||
it( 'should return null for an empty array', () => {
|
||||
const value = getUrlValue( [] );
|
||||
expect( value ).toBeNull();
|
||||
} );
|
||||
|
||||
it( 'should return comma separated values when given an array', () => {
|
||||
const value = getUrlValue( [ 1, 2, 3 ] );
|
||||
expect( value ).toBe( '1,2,3' );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'getQueryFromActiveFilters', () => {
|
||||
it( 'should return a query object from activeFilters', () => {
|
||||
const activeFilters = [
|
||||
|
@ -148,32 +102,27 @@ describe( 'getQueryFromActiveFilters', () => {
|
|||
{
|
||||
key: 'things',
|
||||
rule: 'includes',
|
||||
value: [ 1, 2, 3 ],
|
||||
value: '1,2,3',
|
||||
},
|
||||
{ key: 'customer', value: 'new' },
|
||||
];
|
||||
|
||||
const query = getQueryFromActiveFilters( activeFilters );
|
||||
expect( query.status_is ).toBe( 'open' );
|
||||
expect( query.things_includes ).toBe( '1,2,3' );
|
||||
expect( query.customer ).toBe( 'new' );
|
||||
const query = {};
|
||||
const nextQuery = getQueryFromActiveFilters( activeFilters, query, config );
|
||||
expect( nextQuery.status_is ).toBe( 'open' );
|
||||
expect( nextQuery.things_includes ).toBe( '1,2,3' );
|
||||
expect( nextQuery.customer ).toBe( 'new' );
|
||||
} );
|
||||
|
||||
it( 'should remove parameters from the previous filters', () => {
|
||||
const nextFilters = [];
|
||||
const previousFilters = [
|
||||
{ key: 'status', rule: 'is', value: 'open' },
|
||||
{
|
||||
key: 'things',
|
||||
rule: 'includes',
|
||||
value: [ 1, 2, 3 ],
|
||||
},
|
||||
{ key: 'customer', value: 'new' },
|
||||
];
|
||||
const activeFilters = [];
|
||||
const query = {
|
||||
with_select_is: 'complete',
|
||||
with_search_includes: '45',
|
||||
};
|
||||
|
||||
const query = getQueryFromActiveFilters( nextFilters, previousFilters );
|
||||
expect( query.status_is ).toBeUndefined();
|
||||
expect( query.things_includes ).toBeUndefined();
|
||||
expect( query.customer ).toBeUndefined();
|
||||
const nextQuery = getQueryFromActiveFilters( activeFilters, query, config );
|
||||
expect( nextQuery.with_select_is ).toBeUndefined();
|
||||
expect( nextQuery.with_search_includes ).toBeUndefined();
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -18,23 +18,13 @@ export const getUrlKey = ( key, rule ) => {
|
|||
return key;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert url values to array of objects for <Search /> component
|
||||
*
|
||||
* @param {string} str - url query parameter value
|
||||
* @return {array} - array of Search values
|
||||
*/
|
||||
export const getSearchFilterValue = str => {
|
||||
return str.length ? str.trim().split( ',' ) : [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Describe activeFilter object.
|
||||
*
|
||||
* @typedef {Object} activeFilter
|
||||
* @property {string} key - filter key.
|
||||
* @property {string} [rule] - a modifying rule for a filter, eg 'includes' or 'is_not'.
|
||||
* @property {string|array} value - filter value(s).
|
||||
* @property {string} value - filter value(s).
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -54,9 +44,7 @@ export const getActiveFiltersFromQuery = ( query, config ) => {
|
|||
} );
|
||||
|
||||
if ( match ) {
|
||||
const rawValue = query[ getUrlKey( configKey, match.value ) ];
|
||||
const value =
|
||||
'Search' === filter.input.component ? getSearchFilterValue( rawValue ) : rawValue;
|
||||
const value = query[ getUrlKey( configKey, match.value ) ];
|
||||
return {
|
||||
key: configKey,
|
||||
rule: match.value,
|
||||
|
@ -76,40 +64,27 @@ export const getActiveFiltersFromQuery = ( query, config ) => {
|
|||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a string value for url. Return a string directly or concatenate ids if supplied
|
||||
* an array of objects.
|
||||
*
|
||||
* @param {string|array} value - value of an activeFilter
|
||||
* @return {string|null} - url query param value
|
||||
*/
|
||||
export const getUrlValue = value => {
|
||||
if ( Array.isArray( value ) ) {
|
||||
return value.length ? value.join( ',' ) : null;
|
||||
}
|
||||
return 'string' === typeof value ? value : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given activeFilters, create a new query object to update the url. Use previousFilters to
|
||||
* Remove unused params.
|
||||
*
|
||||
* @param {activeFilters[]} nextFilters - activeFilters shown in the UI
|
||||
* @param {activeFilters[]} previousFilters - filters represented by the current url
|
||||
* @param {activeFilters[]} activeFilters - activeFilters shown in the UI
|
||||
* @param {object} query - the current url query object
|
||||
* @param {object} config - config object
|
||||
* @return {object} - query object representing the new parameters
|
||||
*/
|
||||
export const getQueryFromActiveFilters = ( nextFilters, previousFilters = [] ) => {
|
||||
const previousData = previousFilters.reduce( ( query, filter ) => {
|
||||
query[ getUrlKey( filter.key, filter.rule ) ] = undefined;
|
||||
return query;
|
||||
export const getQueryFromActiveFilters = ( activeFilters, query, config ) => {
|
||||
const previousFilters = getActiveFiltersFromQuery( query, config );
|
||||
const previousData = previousFilters.reduce( ( data, filter ) => {
|
||||
data[ getUrlKey( filter.key, filter.rule ) ] = undefined;
|
||||
return data;
|
||||
}, {} );
|
||||
const data = nextFilters.reduce( ( query, filter ) => {
|
||||
const urlValue = getUrlValue( filter.value );
|
||||
if ( urlValue ) {
|
||||
query[ getUrlKey( filter.key, filter.rule ) ] = urlValue;
|
||||
const nextData = activeFilters.reduce( ( data, filter ) => {
|
||||
if ( filter.value ) {
|
||||
data[ getUrlKey( filter.key, filter.rule ) ] = filter.value;
|
||||
}
|
||||
return query;
|
||||
return data;
|
||||
}, {} );
|
||||
|
||||
return { ...previousData, ...data };
|
||||
return { ...previousData, ...nextData };
|
||||
};
|
||||
|
|
|
@ -46,7 +46,6 @@ class ReportFilters extends Component {
|
|||
return (
|
||||
<div className="woocommerce-filters__advanced-filters">
|
||||
<AdvancedFilters
|
||||
key={ JSON.stringify( query ) }
|
||||
config={ advancedConfig }
|
||||
filterTitle={ __( 'Orders', 'wc-admin' ) }
|
||||
path={ path }
|
||||
|
|
Loading…
Reference in New Issue