diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js index a957e31a9de4..0e57bcf4db03 100644 --- a/src/components/CategoryPicker/index.js +++ b/src/components/CategoryPicker/index.js @@ -1,22 +1,18 @@ import lodashGet from 'lodash/get'; -import React, {useMemo, useState} from 'react'; +import React, {useMemo} from 'react'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -import OptionsSelector from '@components/OptionsSelector'; +import SelectionList from '@components/SelectionList'; +import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {defaultProps, propTypes} from './categoryPickerPropTypes'; function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedCategories, onSubmit}) { - const styles = useThemeStyles(); const {translate} = useLocalize(); - const [searchValue, setSearchValue] = useState(''); - - const policyCategoriesCount = OptionsListUtils.getEnabledCategoriesCount(_.values(policyCategories)); - const isCategoriesCountBelowThreshold = policyCategoriesCount < CONST.CATEGORY_LIST_THRESHOLD; + const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); const selectedOptions = useMemo(() => { if (!selectedCategory) { @@ -28,17 +24,18 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC name: selectedCategory, enabled: true, accountID: null, + isSelected: true, }, ]; }, [selectedCategory]); - const sections = useMemo(() => { + const [sections, headerMessage, policyCategoriesCount, shouldShowTextInput] = useMemo(() => { const validPolicyRecentlyUsedCategories = _.filter(policyRecentlyUsedCategories, (p) => !_.isEmpty(p)); const {categoryOptions} = OptionsListUtils.getFilteredOptions( {}, {}, [], - searchValue, + debouncedSearchValue, selectedOptions, [], false, @@ -49,31 +46,28 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC false, ); - return categoryOptions; - }, [policyCategories, policyRecentlyUsedCategories, searchValue, selectedOptions]); + const header = OptionsListUtils.getHeaderMessageForNonUserList(lodashGet(categoryOptions, '[0].data', []).length > 0, debouncedSearchValue); + const policiesCount = OptionsListUtils.getEnabledCategoriesCount(_.values(policyCategories)); + const isCategoriesCountBelowThreshold = policyCategoriesCount < CONST.CATEGORY_LIST_THRESHOLD; + const showInput = !isCategoriesCountBelowThreshold; + + return [categoryOptions, header, policiesCount, showInput]; + }, [policyCategories, policyRecentlyUsedCategories, debouncedSearchValue, selectedOptions]); - const headerMessage = OptionsListUtils.getHeaderMessageForNonUserList(lodashGet(sections, '[0].data.length', 0) > 0, searchValue); - const shouldShowTextInput = !isCategoriesCountBelowThreshold; - const selectedOptionKey = lodashGet(_.filter(lodashGet(sections, '[0].data', []), (category) => category.searchText === selectedCategory)[0], 'keyForList'); + const selectedOptionKey = useMemo( + () => lodashGet(_.filter(lodashGet(sections, '[0].data', []), (category) => category.searchText === selectedCategory)[0], 'keyForList'), + [sections, selectedCategory], + ); return ( - ); } diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index d6f718da2b2c..80081061f340 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -78,6 +78,7 @@ type CategorySection = { type Category = { name: string; enabled: boolean; + isSelected?: boolean; }; type Hierarchy = Record; @@ -900,6 +901,7 @@ function getCategoryOptionTree(options: Record | Category[], i searchText: option.name, tooltipText: option.name, isDisabled: !option.enabled, + isSelected: !!option.isSelected, }); return; @@ -920,6 +922,7 @@ function getCategoryOptionTree(options: Record | Category[], i searchText, tooltipText: optionName, isDisabled: isChild ? !option.enabled : true, + isSelected: !!option.isSelected, }); }); }); diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index a028f02059d8..00f1307ab59f 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -721,6 +721,7 @@ describe('OptionsListUtils', () => { searchText: 'Food', tooltipText: 'Food', isDisabled: false, + isSelected: false, }, { text: ' Meat', @@ -728,6 +729,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Meat', tooltipText: 'Meat', isDisabled: false, + isSelected: false, }, { text: 'Restaurant', @@ -735,6 +737,7 @@ describe('OptionsListUtils', () => { searchText: 'Restaurant', tooltipText: 'Restaurant', isDisabled: false, + isSelected: false, }, ], }, @@ -751,6 +754,7 @@ describe('OptionsListUtils', () => { searchText: 'Food', tooltipText: 'Food', isDisabled: false, + isSelected: false, }, { text: 'Food: Meat', @@ -758,6 +762,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Meat', tooltipText: 'Food: Meat', isDisabled: false, + isSelected: false, }, ], }, @@ -840,6 +845,7 @@ describe('OptionsListUtils', () => { searchText: 'Medical', tooltipText: 'Medical', isDisabled: false, + isSelected: false, }, ], }, @@ -854,6 +860,7 @@ describe('OptionsListUtils', () => { searchText: 'Restaurant', tooltipText: 'Restaurant', isDisabled: false, + isSelected: false, }, ], }, @@ -868,6 +875,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars', tooltipText: 'Cars', isDisabled: true, + isSelected: false, }, { text: ' Audi', @@ -875,6 +883,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars: Audi', tooltipText: 'Audi', isDisabled: false, + isSelected: false, }, { text: ' Mercedes-Benz', @@ -882,6 +891,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars: Mercedes-Benz', tooltipText: 'Mercedes-Benz', isDisabled: false, + isSelected: false, }, { text: 'Food', @@ -889,6 +899,7 @@ describe('OptionsListUtils', () => { searchText: 'Food', tooltipText: 'Food', isDisabled: false, + isSelected: false, }, { text: ' Meat', @@ -896,6 +907,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Meat', tooltipText: 'Meat', isDisabled: false, + isSelected: false, }, { text: ' Milk', @@ -903,6 +915,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Milk', tooltipText: 'Milk', isDisabled: false, + isSelected: false, }, { text: 'Restaurant', @@ -910,6 +923,7 @@ describe('OptionsListUtils', () => { searchText: 'Restaurant', tooltipText: 'Restaurant', isDisabled: false, + isSelected: false, }, { text: 'Travel', @@ -917,6 +931,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel', tooltipText: 'Travel', isDisabled: true, + isSelected: false, }, { text: ' Meals', @@ -924,6 +939,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals', tooltipText: 'Meals', isDisabled: false, + isSelected: false, }, { text: ' Breakfast', @@ -931,6 +947,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals: Breakfast', tooltipText: 'Breakfast', isDisabled: false, + isSelected: false, }, { text: ' Lunch', @@ -938,6 +955,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals: Lunch', tooltipText: 'Lunch', isDisabled: false, + isSelected: false, }, ], }, @@ -954,6 +972,7 @@ describe('OptionsListUtils', () => { searchText: 'Food', tooltipText: 'Food', isDisabled: false, + isSelected: false, }, { text: 'Food: Meat', @@ -961,6 +980,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Meat', tooltipText: 'Food: Meat', isDisabled: false, + isSelected: false, }, { text: 'Food: Milk', @@ -968,6 +988,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Milk', tooltipText: 'Food: Milk', isDisabled: false, + isSelected: false, }, ], }, @@ -993,6 +1014,7 @@ describe('OptionsListUtils', () => { searchText: 'Medical', tooltipText: 'Medical', isDisabled: false, + isSelected: false, }, ], }, @@ -1439,6 +1461,7 @@ describe('OptionsListUtils', () => { searchText: 'Meals', tooltipText: 'Meals', isDisabled: false, + isSelected: false, }, { text: 'Restaurant', @@ -1446,6 +1469,7 @@ describe('OptionsListUtils', () => { searchText: 'Restaurant', tooltipText: 'Restaurant', isDisabled: false, + isSelected: false, }, { text: 'Food', @@ -1453,6 +1477,7 @@ describe('OptionsListUtils', () => { searchText: 'Food', tooltipText: 'Food', isDisabled: false, + isSelected: false, }, { text: ' Meat', @@ -1460,6 +1485,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Meat', tooltipText: 'Meat', isDisabled: false, + isSelected: false, }, { text: ' Milk', @@ -1467,6 +1493,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Milk', tooltipText: 'Milk', isDisabled: false, + isSelected: false, }, { text: 'Cars', @@ -1474,6 +1501,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars', tooltipText: 'Cars', isDisabled: true, + isSelected: false, }, { text: ' Audi', @@ -1481,6 +1509,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars: Audi', tooltipText: 'Audi', isDisabled: false, + isSelected: false, }, { text: ' Mercedes-Benz', @@ -1488,6 +1517,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars: Mercedes-Benz', tooltipText: 'Mercedes-Benz', isDisabled: false, + isSelected: false, }, { text: 'Travel', @@ -1495,6 +1525,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel', tooltipText: 'Travel', isDisabled: true, + isSelected: false, }, { text: ' Meals', @@ -1502,6 +1533,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals', tooltipText: 'Meals', isDisabled: false, + isSelected: false, }, { text: ' Breakfast', @@ -1509,6 +1541,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals: Breakfast', tooltipText: 'Breakfast', isDisabled: false, + isSelected: false, }, { text: ' Lunch', @@ -1516,6 +1549,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals: Lunch', tooltipText: 'Lunch', isDisabled: false, + isSelected: false, }, { text: 'Plain', @@ -1523,6 +1557,7 @@ describe('OptionsListUtils', () => { searchText: 'Plain', tooltipText: 'Plain', isDisabled: false, + isSelected: false, }, { text: 'Audi', @@ -1530,6 +1565,7 @@ describe('OptionsListUtils', () => { searchText: 'Audi', tooltipText: 'Audi', isDisabled: false, + isSelected: false, }, { text: 'Health', @@ -1537,6 +1573,7 @@ describe('OptionsListUtils', () => { searchText: 'Health', tooltipText: 'Health', isDisabled: false, + isSelected: false, }, { text: 'A', @@ -1544,6 +1581,7 @@ describe('OptionsListUtils', () => { searchText: 'A', tooltipText: 'A', isDisabled: true, + isSelected: false, }, { text: ' B', @@ -1551,6 +1589,7 @@ describe('OptionsListUtils', () => { searchText: 'A: B', tooltipText: 'B', isDisabled: true, + isSelected: false, }, { text: ' C', @@ -1558,6 +1597,7 @@ describe('OptionsListUtils', () => { searchText: 'A: B: C', tooltipText: 'C', isDisabled: false, + isSelected: false, }, { text: ' D', @@ -1565,6 +1605,7 @@ describe('OptionsListUtils', () => { searchText: 'A: B: C: D', tooltipText: 'D', isDisabled: true, + isSelected: false, }, { text: ' E', @@ -1572,6 +1613,7 @@ describe('OptionsListUtils', () => { searchText: 'A: B: C: D: E', tooltipText: 'E', isDisabled: false, + isSelected: false, }, ]; const resultOneLine = [ @@ -1581,6 +1623,7 @@ describe('OptionsListUtils', () => { searchText: 'Meals', tooltipText: 'Meals', isDisabled: false, + isSelected: false, }, { text: 'Restaurant', @@ -1588,6 +1631,7 @@ describe('OptionsListUtils', () => { searchText: 'Restaurant', tooltipText: 'Restaurant', isDisabled: false, + isSelected: false, }, { text: 'Food', @@ -1595,6 +1639,7 @@ describe('OptionsListUtils', () => { searchText: 'Food', tooltipText: 'Food', isDisabled: false, + isSelected: false, }, { text: 'Food: Meat', @@ -1602,6 +1647,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Meat', tooltipText: 'Food: Meat', isDisabled: false, + isSelected: false, }, { text: 'Food: Milk', @@ -1609,6 +1655,7 @@ describe('OptionsListUtils', () => { searchText: 'Food: Milk', tooltipText: 'Food: Milk', isDisabled: false, + isSelected: false, }, { text: 'Cars: Audi', @@ -1616,6 +1663,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars: Audi', tooltipText: 'Cars: Audi', isDisabled: false, + isSelected: false, }, { text: 'Cars: Mercedes-Benz', @@ -1623,6 +1671,7 @@ describe('OptionsListUtils', () => { searchText: 'Cars: Mercedes-Benz', tooltipText: 'Cars: Mercedes-Benz', isDisabled: false, + isSelected: false, }, { text: 'Travel: Meals', @@ -1630,6 +1679,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals', tooltipText: 'Travel: Meals', isDisabled: false, + isSelected: false, }, { text: 'Travel: Meals: Breakfast', @@ -1637,6 +1687,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals: Breakfast', tooltipText: 'Travel: Meals: Breakfast', isDisabled: false, + isSelected: false, }, { text: 'Travel: Meals: Lunch', @@ -1644,6 +1695,7 @@ describe('OptionsListUtils', () => { searchText: 'Travel: Meals: Lunch', tooltipText: 'Travel: Meals: Lunch', isDisabled: false, + isSelected: false, }, { text: 'Plain', @@ -1651,6 +1703,7 @@ describe('OptionsListUtils', () => { searchText: 'Plain', tooltipText: 'Plain', isDisabled: false, + isSelected: false, }, { text: 'Audi', @@ -1658,6 +1711,7 @@ describe('OptionsListUtils', () => { searchText: 'Audi', tooltipText: 'Audi', isDisabled: false, + isSelected: false, }, { text: 'Health', @@ -1665,6 +1719,7 @@ describe('OptionsListUtils', () => { searchText: 'Health', tooltipText: 'Health', isDisabled: false, + isSelected: false, }, { text: 'A: B: C', @@ -1672,6 +1727,7 @@ describe('OptionsListUtils', () => { searchText: 'A: B: C', tooltipText: 'A: B: C', isDisabled: false, + isSelected: false, }, { text: 'A: B: C: D: E', @@ -1679,6 +1735,7 @@ describe('OptionsListUtils', () => { searchText: 'A: B: C: D: E', tooltipText: 'A: B: C: D: E', isDisabled: false, + isSelected: false, }, ];