Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit b6caa1d

Browse files
authored
Fix: Convert Active Filters Block codebase to TypeScript (#6580)
1 parent 83331a5 commit b6caa1d

File tree

17 files changed

+282
-100
lines changed

17 files changed

+282
-100
lines changed

assets/js/base/components/chip/chip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export interface ChipProps {
1212
/**
1313
* Text for chip content.
1414
*/
15-
text: string;
15+
text: string | JSX.Element;
1616
/**
1717
* Screenreader text for the content.
1818
*/

assets/js/blocks/active-filters/active-attribute-filters.js renamed to assets/js/blocks/active-filters/active-attribute-filters.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,26 @@ import {
88
import { decodeEntities } from '@wordpress/html-entities';
99
import { __ } from '@wordpress/i18n';
1010
import { getSettingWithCoercion } from '@woocommerce/settings';
11-
import { isBoolean } from '@woocommerce/types';
11+
import {
12+
AttributeObject,
13+
isAttributeQueryCollection,
14+
isAttributeTermCollection,
15+
isBoolean,
16+
} from '@woocommerce/types';
1217

1318
/**
1419
* Internal dependencies
1520
*/
1621
import { renderRemovableListItem, removeArgsFromFilterUrl } from './utils';
1722
import { removeAttributeFilterBySlug } from '../../utils/attributes-query';
1823

24+
interface ActiveAttributeFiltersProps {
25+
displayStyle: string;
26+
operator: 'and' | 'in';
27+
slugs: string[];
28+
attributeObject: AttributeObject;
29+
}
30+
1931
/**
2032
* Component that renders active attribute (terms) filters.
2133
*
@@ -26,11 +38,11 @@ import { removeAttributeFilterBySlug } from '../../utils/attributes-query';
2638
* @param {string} props.displayStyle The style used for displaying the filters.
2739
*/
2840
const ActiveAttributeFilters = ( {
29-
attributeObject = {},
41+
attributeObject,
3042
slugs = [],
3143
operator = 'in',
3244
displayStyle,
33-
} ) => {
45+
}: ActiveAttributeFiltersProps ) => {
3446
const { results, isLoading } = useCollection( {
3547
namespace: '/wc/store/v1',
3648
resourceName: 'products/attributes/terms',
@@ -42,7 +54,12 @@ const ActiveAttributeFilters = ( {
4254
[]
4355
);
4456

45-
if ( isLoading ) {
57+
if (
58+
isLoading ||
59+
! Array.isArray( results ) ||
60+
! isAttributeTermCollection( results ) ||
61+
! isAttributeQueryCollection( productAttributes )
62+
) {
4663
return null;
4764
}
4865

@@ -69,7 +86,7 @@ const ActiveAttributeFilters = ( {
6986
return null;
7087
}
7188

72-
let prefix = '';
89+
let prefix: string | JSX.Element = '';
7390

7491
if ( index > 0 && operator === 'and' ) {
7592
prefix = (
@@ -92,7 +109,7 @@ const ActiveAttributeFilters = ( {
92109
);
93110

94111
// If only one attribute was selected, we remove both filter and query type from the URL.
95-
if ( currentAttribute.slug.length === 1 ) {
112+
if ( currentAttribute?.slug.length === 1 ) {
96113
return removeArgsFromFilterUrl(
97114
`query_type_${ attributeObject.name }`,
98115
`filter_${ attributeObject.name }`
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
6+
export const blockAttributes = {
7+
heading: {
8+
type: 'string',
9+
default: __( 'Active filters', 'woo-gutenberg-products-block' ),
10+
},
11+
};
Lines changed: 76 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ import { useMemo, useEffect } from '@wordpress/element';
88
import classnames from 'classnames';
99
import PropTypes from 'prop-types';
1010
import Label from '@woocommerce/base-components/label';
11-
import { isBoolean } from '@woocommerce/types';
11+
import {
12+
isAttributeQueryCollection,
13+
isBoolean,
14+
isRatingQueryCollection,
15+
isStockStatusQueryCollection,
16+
isStockStatusOptions,
17+
} from '@woocommerce/types';
1218
import { getUrlParameter } from '@woocommerce/utils';
1319

1420
/**
@@ -23,6 +29,7 @@ import {
2329
cleanFilterUrl,
2430
} from './utils';
2531
import ActiveAttributeFilters from './active-attribute-filters';
32+
import { Attributes } from './types';
2633

2734
/**
2835
* Component displaying active filters.
@@ -34,6 +41,9 @@ import ActiveAttributeFilters from './active-attribute-filters';
3441
const ActiveFiltersBlock = ( {
3542
attributes: blockAttributes,
3643
isEditor = false,
44+
}: {
45+
attributes: Attributes;
46+
isEditor?: boolean;
3747
} ) => {
3848
const filteringForPhpTemplate = getSettingWithCoercion(
3949
'is_rendering_php_template',
@@ -53,28 +63,34 @@ const ActiveFiltersBlock = ( {
5363

5464
const STOCK_STATUS_OPTIONS = getSetting( 'stockStatusOptions', [] );
5565
const activeStockStatusFilters = useMemo( () => {
56-
if ( productStockStatus.length > 0 ) {
57-
return productStockStatus.map( ( slug ) => {
58-
return renderRemovableListItem( {
59-
type: __( 'Stock Status', 'woo-gutenberg-products-block' ),
60-
name: STOCK_STATUS_OPTIONS[ slug ],
61-
removeCallback: () => {
62-
if ( filteringForPhpTemplate ) {
63-
return removeArgsFromFilterUrl( {
64-
filter_stock_status: slug,
65-
} );
66+
if (
67+
productStockStatus.length === 0 ||
68+
! isStockStatusQueryCollection( productStockStatus ) ||
69+
! isStockStatusOptions( STOCK_STATUS_OPTIONS )
70+
) {
71+
return null;
72+
}
73+
74+
return productStockStatus.map( ( slug ) => {
75+
return renderRemovableListItem( {
76+
type: __( 'Stock Status', 'woo-gutenberg-products-block' ),
77+
name: STOCK_STATUS_OPTIONS[ slug ],
78+
removeCallback: () => {
79+
if ( filteringForPhpTemplate ) {
80+
return removeArgsFromFilterUrl( {
81+
filter_stock_status: slug,
82+
} );
83+
}
84+
const newStatuses = productStockStatus.filter(
85+
( status ) => {
86+
return status !== slug;
6687
}
67-
const newStatuses = productStockStatus.filter(
68-
( status ) => {
69-
return status !== slug;
70-
}
71-
);
72-
setProductStockStatus( newStatuses );
73-
},
74-
displayStyle: blockAttributes.displayStyle,
75-
} );
88+
);
89+
setProductStockStatus( newStatuses );
90+
},
91+
displayStyle: blockAttributes.displayStyle,
7692
} );
77-
}
93+
} );
7894
}, [
7995
STOCK_STATUS_OPTIONS,
8096
productStockStatus,
@@ -109,10 +125,19 @@ const ActiveFiltersBlock = ( {
109125
] );
110126

111127
const activeAttributeFilters = useMemo( () => {
128+
if ( ! isAttributeQueryCollection( productAttributes ) ) {
129+
return null;
130+
}
131+
112132
return productAttributes.map( ( attribute ) => {
113133
const attributeObject = getAttributeFromTaxonomy(
114134
attribute.attribute
115135
);
136+
137+
if ( ! attributeObject ) {
138+
return null;
139+
}
140+
116141
return (
117142
<ActiveAttributeFilters
118143
attributeObject={ attributeObject }
@@ -151,35 +176,35 @@ const ActiveFiltersBlock = ( {
151176
}, [ filteringForPhpTemplate, productRatings, setProductRatings ] );
152177

153178
const activeRatingFilters = useMemo( () => {
154-
if ( productRatings.length > 0 ) {
155-
return productRatings.map( ( slug ) => {
156-
return renderRemovableListItem( {
157-
type: __( 'Rating', 'woo-gutenberg-products-block' ),
158-
name: sprintf(
159-
/* translators: %s is referring to the average rating value */
160-
__(
161-
'Rated %s out of 5',
162-
'woo-gutenberg-products-block'
163-
),
164-
slug
165-
),
166-
removeCallback: () => {
167-
if ( filteringForPhpTemplate ) {
168-
return removeArgsFromFilterUrl( {
169-
rating_filter: slug,
170-
} );
171-
}
172-
const newRatings = productRatings.filter(
173-
( rating ) => {
174-
return rating !== slug;
175-
}
176-
);
177-
setProductRatings( newRatings );
178-
},
179-
displayStyle: blockAttributes.displayStyle,
180-
} );
181-
} );
179+
if (
180+
productRatings.length === 0 ||
181+
! isRatingQueryCollection( productRatings )
182+
) {
183+
return null;
182184
}
185+
186+
return productRatings.map( ( slug ) => {
187+
return renderRemovableListItem( {
188+
type: __( 'Rating', 'woo-gutenberg-products-block' ),
189+
name: sprintf(
190+
/* translators: %s is referring to the average rating value */
191+
__( 'Rated %s out of 5', 'woo-gutenberg-products-block' ),
192+
slug
193+
),
194+
removeCallback: () => {
195+
if ( filteringForPhpTemplate ) {
196+
return removeArgsFromFilterUrl( {
197+
rating_filter: slug,
198+
} );
199+
}
200+
const newRatings = productRatings.filter( ( rating ) => {
201+
return rating !== slug;
202+
} );
203+
setProductRatings( newRatings );
204+
},
205+
displayStyle: blockAttributes.displayStyle,
206+
} );
207+
} );
183208
}, [
184209
productRatings,
185210
setProductRatings,
@@ -201,7 +226,8 @@ const ActiveFiltersBlock = ( {
201226
return null;
202227
}
203228

204-
const TagName = `h${ blockAttributes.headingLevel }`;
229+
const TagName =
230+
`h${ blockAttributes.headingLevel }` as keyof JSX.IntrinsicElements;
205231
const hasFilterableProducts = getSettingWithCoercion(
206232
'has_filterable_products',
207233
false,
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { __ } from '@wordpress/i18n';
55
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
66
import HeadingToolbar from '@woocommerce/editor-components/heading-toolbar';
77
import BlockTitle from '@woocommerce/editor-components/block-title';
8+
import type { BlockEditProps } from '@wordpress/blocks';
89
import {
910
Disabled,
1011
PanelBody,
@@ -18,9 +19,13 @@ import {
1819
/**
1920
* Internal dependencies
2021
*/
21-
import Block from './block.js';
22+
import Block from './block';
23+
import type { Attributes } from './types';
2224

23-
const Edit = ( { attributes, setAttributes } ) => {
25+
const Edit = ( {
26+
attributes,
27+
setAttributes,
28+
}: BlockEditProps< Attributes > ) => {
2429
const { className, displayStyle, heading, headingLevel } = attributes;
2530

2631
const blockProps = useBlockProps( {
@@ -42,7 +47,7 @@ const Edit = ( { attributes, setAttributes } ) => {
4247
'woo-gutenberg-products-block'
4348
) }
4449
value={ displayStyle }
45-
onChange={ ( value ) =>
50+
onChange={ ( value: Attributes[ 'displayStyle' ] ) =>
4651
setAttributes( {
4752
displayStyle: value,
4853
} )
@@ -74,7 +79,7 @@ const Edit = ( { attributes, setAttributes } ) => {
7479
minLevel={ 2 }
7580
maxLevel={ 7 }
7681
selectedLevel={ headingLevel }
77-
onChange={ ( newLevel ) =>
82+
onChange={ ( newLevel: Attributes[ 'headingLevel' ] ) =>
7883
setAttributes( { headingLevel: newLevel } )
7984
}
8085
/>
@@ -90,7 +95,9 @@ const Edit = ( { attributes, setAttributes } ) => {
9095
className="wc-block-active-filters__title"
9196
headingLevel={ headingLevel }
9297
heading={ heading }
93-
onChange={ ( value ) => setAttributes( { heading: value } ) }
98+
onChange={ ( value: Attributes[ 'heading' ] ) =>
99+
setAttributes( { heading: value } )
100+
}
94101
/>
95102
<Disabled>
96103
<Block attributes={ attributes } isEditor={ true } />

assets/js/blocks/active-filters/frontend.js

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { renderFrontend } from '@woocommerce/base-utils';
5+
6+
/**
7+
* Internal dependencies
8+
*/
9+
import Block from './block';
10+
import metadata from './block.json';
11+
import { blockAttributes } from './attributes';
12+
13+
const getProps = ( el: HTMLElement ) => {
14+
return {
15+
attributes: {
16+
displayStyle:
17+
el.dataset.displayStyle ||
18+
metadata.attributes.displayStyle.default,
19+
heading: el.dataset.heading || blockAttributes.heading.default,
20+
headingLevel: el.dataset.headingLevel
21+
? parseInt( el.dataset.headingLevel, 10 )
22+
: metadata.attributes.headingLevel.default,
23+
},
24+
isEditor: false,
25+
};
26+
};
27+
28+
renderFrontend( {
29+
selector: '.wp-block-woocommerce-active-filters',
30+
Block,
31+
getProps,
32+
} );

0 commit comments

Comments
 (0)