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

Commit 8344018

Browse files
authored
Fix: Convert Filter Products by Stock to TypeScript (#6533)
1 parent 296ccef commit 8344018

File tree

10 files changed

+106
-47
lines changed

10 files changed

+106
-47
lines changed

assets/js/base/components/filter-element-label/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import './style.scss';
1111

1212
interface FilterElementLabelProps {
1313
name: string;
14-
count: number;
14+
count: number | null;
1515
}
1616
/**
1717
* The label for an filter elements.
@@ -27,7 +27,7 @@ const FilterElementLabel = ( {
2727
return (
2828
<>
2929
{ name }
30-
{ Number.isFinite( count ) && (
30+
{ count && Number.isFinite( count ) && (
3131
<Label
3232
label={ count.toString() }
3333
screenReaderLabel={ sprintf(
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: __( 'Filter by stock status', 'woo-gutenberg-products-block' ),
10+
},
11+
};

assets/js/blocks/stock-filter/block.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
}
1616
},
1717
"attributes": {
18+
"className": {
19+
"type": "string",
20+
"default": ""
21+
},
1822
"headingLevel": {
1923
"type": "number",
2024
"default": 3
Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,19 @@ import {
1010
useCollectionData,
1111
} from '@woocommerce/base-context/hooks';
1212
import { getSetting, getSettingWithCoercion } from '@woocommerce/settings';
13-
import { useCallback, useEffect, useState, useMemo } from '@wordpress/element';
13+
import {
14+
useCallback,
15+
useEffect,
16+
useState,
17+
useMemo,
18+
useRef,
19+
} from '@wordpress/element';
1420
import CheckboxList from '@woocommerce/base-components/checkbox-list';
1521
import FilterSubmitButton from '@woocommerce/base-components/filter-submit-button';
1622
import Label from '@woocommerce/base-components/filter-element-label';
1723
import isShallowEqual from '@wordpress/is-shallow-equal';
1824
import { decodeEntities } from '@wordpress/html-entities';
19-
import { isBoolean } from '@woocommerce/types';
25+
import { isBoolean, objectHasProp } from '@woocommerce/types';
2026
import { addQueryArgs, removeQueryArgs } from '@wordpress/url';
2127
import { PREFIX_QUERY_ARG_FILTER_TYPE } from '@woocommerce/utils';
2228

@@ -26,6 +32,7 @@ import { PREFIX_QUERY_ARG_FILTER_TYPE } from '@woocommerce/utils';
2632
import { previewOptions } from './preview';
2733
import './style.scss';
2834
import { getActiveFilters } from './utils';
35+
import { Attributes, DisplayOption } from './types';
2936

3037
export const QUERY_PARAM_KEY = PREFIX_QUERY_ARG_FILTER_TYPE + 'stock_status';
3138

@@ -39,6 +46,9 @@ export const QUERY_PARAM_KEY = PREFIX_QUERY_ARG_FILTER_TYPE + 'stock_status';
3946
const StockStatusFilterBlock = ( {
4047
attributes: blockAttributes,
4148
isEditor = false,
49+
}: {
50+
attributes: Attributes;
51+
isEditor?: boolean;
4252
} ) => {
4353
const filteringForPhpTemplate = getSettingWithCoercion(
4454
'is_rendering_php_template',
@@ -50,27 +60,26 @@ const StockStatusFilterBlock = ( {
5060
false
5161
);
5262

53-
const [ hideOutOfStockItems ] = useState(
54-
getSetting( 'hideOutOfStockItems', false )
63+
const { outofstock, ...otherStockStatusOptions } = getSetting(
64+
'stockStatusOptions',
65+
{}
5566
);
56-
const [ { outofstock, ...otherStockStatusOptions } ] = useState(
57-
getSetting( 'stockStatusOptions', {} )
58-
);
59-
const [ STOCK_STATUS_OPTIONS ] = useState(
60-
hideOutOfStockItems
67+
68+
const STOCK_STATUS_OPTIONS = useRef(
69+
getSetting( 'hideOutOfStockItems', false )
6170
? otherStockStatusOptions
6271
: { outofstock, ...otherStockStatusOptions }
6372
);
6473

6574
const [ checked, setChecked ] = useState(
66-
getActiveFilters( STOCK_STATUS_OPTIONS, QUERY_PARAM_KEY )
75+
getActiveFilters( STOCK_STATUS_OPTIONS.current, QUERY_PARAM_KEY )
6776
);
6877
const [ displayedOptions, setDisplayedOptions ] = useState(
6978
blockAttributes.isPreview ? previewOptions : []
7079
);
7180
// Filter added to handle if there are slugs without a corresponding name defined.
7281
const [ initialOptions ] = useState(
73-
Object.entries( STOCK_STATUS_OPTIONS )
82+
Object.entries( STOCK_STATUS_OPTIONS.current )
7483
.map( ( [ slug, name ] ) => ( { slug, name } ) )
7584
.filter( ( status ) => !! status.name )
7685
.sort( ( a, b ) => a.slug.localeCompare( b.slug ) )
@@ -95,7 +104,10 @@ const StockStatusFilterBlock = ( {
95104
*/
96105
const getFilteredStock = useCallback(
97106
( slug ) => {
98-
if ( ! filteredCounts.stock_status_counts ) {
107+
if (
108+
! objectHasProp( filteredCounts, 'stock_status_counts' ) ||
109+
! Array.isArray( filteredCounts.stock_status_counts )
110+
) {
99111
return null;
100112
}
101113
return filteredCounts.stock_status_counts.find(
@@ -115,12 +127,13 @@ const StockStatusFilterBlock = ( {
115127
*
116128
* @param {string} queryStatus The status slug to check.
117129
*/
118-
const isStockStatusInQueryState = ( queryStatus ) => {
130+
const isStockStatusInQueryState = ( queryStatus: string ) => {
119131
if ( ! queryState?.stock_status ) {
120132
return false;
121133
}
122-
return queryState.stock_status.some( ( { status = [] } ) =>
123-
status.includes( queryStatus )
134+
return queryState.stock_status.some(
135+
( { status = [] }: { status: string[] } ) =>
136+
status.includes( queryStatus )
124137
);
125138
};
126139

@@ -153,7 +166,7 @@ const StockStatusFilterBlock = ( {
153166
),
154167
};
155168
} )
156-
.filter( Boolean );
169+
.filter( ( option ): option is DisplayOption => !! option );
157170

158171
setDisplayedOptions( newOptions );
159172
}, [
@@ -171,7 +184,7 @@ const StockStatusFilterBlock = ( {
171184
*
172185
* @param {Array} checkedOptions Array of checked stock options.
173186
*/
174-
const redirectPageForPhpTemplate = ( checkedOptions ) => {
187+
const redirectPageForPhpTemplate = ( checkedOptions: string[] ) => {
175188
if ( checkedOptions.length === 0 ) {
176189
const url = removeQueryArgs(
177190
window.location.href,
@@ -252,12 +265,14 @@ const StockStatusFilterBlock = ( {
252265
useEffect( () => {
253266
if ( ! hasSetPhpFilterDefaults && filteringForPhpTemplate ) {
254267
setProductStockStatusQuery(
255-
getActiveFilters( STOCK_STATUS_OPTIONS, QUERY_PARAM_KEY )
268+
getActiveFilters(
269+
STOCK_STATUS_OPTIONS.current,
270+
QUERY_PARAM_KEY
271+
)
256272
);
257273
setHasSetPhpFilterDefaults( true );
258274
}
259275
}, [
260-
STOCK_STATUS_OPTIONS,
261276
filteringForPhpTemplate,
262277
setProductStockStatusQuery,
263278
hasSetPhpFilterDefaults,
@@ -269,15 +284,22 @@ const StockStatusFilterBlock = ( {
269284
*/
270285
const onChange = useCallback(
271286
( checkedValue ) => {
272-
const getFilterNameFromValue = ( filterValue ) => {
273-
const { name } = displayedOptions.find(
287+
const getFilterNameFromValue = ( filterValue: string ) => {
288+
const filterOption = displayedOptions.find(
274289
( option ) => option.value === filterValue
275290
);
276291

277-
return name;
292+
if ( ! filterOption ) {
293+
return null;
294+
}
295+
296+
return filterOption.name;
278297
};
279298

280-
const announceFilterChange = ( { filterAdded, filterRemoved } ) => {
299+
const announceFilterChange = ( {
300+
filterAdded,
301+
filterRemoved,
302+
}: Record< string, string > ) => {
281303
const filterAddedName = filterAdded
282304
? getFilterNameFromValue( filterAdded )
283305
: null;
@@ -332,8 +354,9 @@ const StockStatusFilterBlock = ( {
332354
return null;
333355
}
334356

335-
const TagName = `h${ blockAttributes.headingLevel }`;
336-
const isLoading = ! blockAttributes.isPreview && ! STOCK_STATUS_OPTIONS;
357+
const TagName = `h${ blockAttributes.headingLevel }` as keyof JSX.IntrinsicElements;
358+
const isLoading =
359+
! blockAttributes.isPreview && ! STOCK_STATUS_OPTIONS.current;
337360
const isDisabled = ! blockAttributes.isPreview && filteredCountsLoading;
338361

339362
const hasFilterableProducts = getSettingWithCoercion(
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ import {
1212
} from '@wordpress/components';
1313
import HeadingToolbar from '@woocommerce/editor-components/heading-toolbar';
1414
import BlockTitle from '@woocommerce/editor-components/block-title';
15+
import type { BlockEditProps } from '@wordpress/blocks';
1516

1617
/**
1718
* Internal dependencies
1819
*/
19-
import Block from './block.js';
20+
import Block from './block';
2021
import './editor.scss';
22+
import { Attributes } from './types';
2123

22-
const Edit = ( { attributes, setAttributes } ) => {
24+
const Edit = ( {
25+
attributes,
26+
setAttributes,
27+
}: BlockEditProps< Attributes > ) => {
2328
const {
2429
className,
2530
heading,
@@ -72,7 +77,7 @@ const Edit = ( { attributes, setAttributes } ) => {
7277
minLevel={ 2 }
7378
maxLevel={ 7 }
7479
selectedLevel={ headingLevel }
75-
onChange={ ( newLevel ) =>
80+
onChange={ ( newLevel: number ) =>
7681
setAttributes( { headingLevel: newLevel } )
7782
}
7883
/>
@@ -120,7 +125,7 @@ const Edit = ( { attributes, setAttributes } ) => {
120125
className="wc-block-stock-filter__title"
121126
headingLevel={ headingLevel }
122127
heading={ heading }
123-
onChange={ ( value ) =>
128+
onChange={ ( value: string ) =>
124129
setAttributes( { heading: value } )
125130
}
126131
/>
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ import { renderFrontend } from '@woocommerce/base-utils';
66
/**
77
* Internal dependencies
88
*/
9-
import Block from './block.js';
9+
import Block from './block';
10+
import metadata from './block.json';
11+
import { blockAttributes } from './attributes';
1012

11-
const getProps = ( el ) => {
13+
const getProps = ( el: HTMLElement ) => {
1214
return {
1315
attributes: {
1416
showCounts: el.dataset.showCounts === 'true',
15-
heading: el.dataset.heading,
16-
headingLevel: el.dataset.headingLevel || 3,
17+
heading: el.dataset.heading || blockAttributes.heading.default,
18+
headingLevel: el.dataset.headingLevel
19+
? parseInt( el.dataset.headingLevel, 10 )
20+
: metadata.attributes.headingLevel.default,
1721
showFilterButton: el.dataset.showFilterButton === 'true',
1822
},
1923
isEditor: false,
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import { useBlockProps } from '@wordpress/block-editor';
1010
/**
1111
* Internal dependencies
1212
*/
13-
import edit from './edit.js';
13+
import edit from './edit';
1414
import metadata from './block.json';
15+
import { blockAttributes } from './attributes';
16+
import type { Attributes } from './types';
1517

1618
registerBlockType( metadata, {
1719
title: __( 'Filter Products by Stock', 'woo-gutenberg-products-block' ),
@@ -29,25 +31,19 @@ registerBlockType( metadata, {
2931
},
3032
attributes: {
3133
...metadata.attributes,
32-
heading: {
33-
type: 'string',
34-
default: __(
35-
'Filter by stock status',
36-
'woo-gutenberg-products-block'
37-
),
38-
},
34+
...blockAttributes,
3935
},
4036
edit,
4137
// Save the props to post content.
42-
save( { attributes } ) {
38+
save( { attributes }: { attributes: Attributes } ) {
4339
const {
4440
className,
4541
showCounts,
4642
heading,
4743
headingLevel,
4844
showFilterButton,
4945
} = attributes;
50-
const data = {
46+
const data: Record< string, unknown > = {
5147
'data-show-counts': showCounts,
5248
'data-heading': heading,
5349
'data-heading-level': headingLevel,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export interface Attributes {
2+
className?: string;
3+
heading: string;
4+
headingLevel: number;
5+
showCounts: boolean;
6+
showFilterButton: boolean;
7+
isPreview?: boolean;
8+
}
9+
10+
export interface DisplayOption {
11+
value: string;
12+
name: string;
13+
label: JSX.Element;
14+
}

assets/js/blocks/stock-filter/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ import { getUrlParameter } from '@woocommerce/utils';
66

77
export const getActiveFilters = (
88
filters: Record< string, string >,
9-
queryParamKey: 'filter_stock_status'
9+
queryParamKey = 'filter_stock_status'
1010
) => {
1111
const params = getUrlParameter( queryParamKey );
1212

1313
if ( ! params ) {
1414
return [];
1515
}
1616

17-
const parsedParams = isString( params ) ? params.split( ',' ) : params;
17+
const parsedParams = isString( params )
18+
? params.split( ',' )
19+
: ( params as string[] );
1820

1921
return Object.keys( filters ).filter( ( filter ) =>
2022
parsedParams.includes( filter )

0 commit comments

Comments
 (0)