diff --git a/client/src/components/AccountsSuggestField.js b/client/src/components/AccountsSuggestField.js new file mode 100644 index 000000000..7fba6a5cb --- /dev/null +++ b/client/src/components/AccountsSuggestField.js @@ -0,0 +1,130 @@ +import React, { useState, useCallback, useEffect, useMemo } from 'react'; +import { MenuItem } from '@blueprintjs/core'; +import { Suggest } from '@blueprintjs/select'; +import { isEmpty } from 'lodash'; + +import classNames from 'classnames'; +import { CLASSES } from 'common/classes'; + +import { FormattedMessage as T } from 'react-intl'; + +export default function AccountsSuggestField({ + accounts, + initialAccountId, + selectedAccountId, + defaultSelectText = 'Select account', + onAccountSelected, + + filterByRootTypes = [], + filterByTypes = [], + filterByNormal, + popoverFill = false, + + ...suggestProps +}) { + // Filters accounts based on filter props. + const filteredAccounts = useMemo(() => { + let filteredAccounts = [...accounts]; + + if (!isEmpty(filterByRootTypes)) { + filteredAccounts = filteredAccounts.filter( + (account) => filterByRootTypes.indexOf(account.type.root_type) !== -1, + ); + } + if (!isEmpty(filterByTypes)) { + filteredAccounts = filteredAccounts.filter( + (account) => filterByTypes.indexOf(account.type.key) !== -1, + ); + } + if (!isEmpty(filterByNormal)) { + filteredAccounts = filteredAccounts.filter( + (account) => + filterByTypes.indexOf(account.type.normal) === filterByNormal, + ); + } + return filteredAccounts; + }, [accounts, filterByRootTypes, filterByTypes, filterByNormal]); + + // Find initial account object to set it as default account in initial render. + const initialAccount = useMemo( + () => filteredAccounts.find((a) => a.id === initialAccountId), + [initialAccountId, filteredAccounts], + ); + + const [selectedAccount, setSelectedAccount] = useState( + initialAccount || null, + ); + + useEffect(() => { + if (typeof selectedAccountId !== 'undefined') { + const account = selectedAccountId + ? filteredAccounts.find((a) => a.id === selectedAccountId) + : null; + setSelectedAccount(account); + } + }, [selectedAccountId, filteredAccounts, setSelectedAccount]); + + // Filters accounts items. + const filterAccountsPredicater = useCallback( + (query, account, _index, exactMatch) => { + const normalizedTitle = account.name.toLowerCase(); + const normalizedQuery = query.toLowerCase(); + + if (exactMatch) { + return normalizedTitle === normalizedQuery; + } else { + return ( + `${account.code} ${normalizedTitle}`.indexOf(normalizedQuery) >= 0 + ); + } + }, + [], + ); + + // Account item of select accounts field. + const accountItem = useCallback((item, { handleClick, modifiers, query }) => { + return ( + + ); + }, []); + + const handleInputValueRenderer = (inputValue) => { + if (inputValue) { + return inputValue.name.toString(); + } + return ''; + }; + + const onAccountSelect = useCallback( + (account) => { + setSelectedAccount({ ...account }); + onAccountSelected && onAccountSelected(account); + }, + [setSelectedAccount, onAccountSelected], + ); + + return ( + } />} + itemRenderer={accountItem} + itemPredicate={filterAccountsPredicater} + onItemSelect={onAccountSelect} + selectedItem={selectedAccount} + inputProps={{ placeholder: defaultSelectText }} + resetOnClose={true} + fill={true} + popoverProps={{ minimal: true }} + {...suggestProps} + inputValueRenderer={handleInputValueRenderer} + className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, { + [CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill, + })} + /> + ); +} diff --git a/client/src/components/DataTableCells/AccountsListFieldCell.js b/client/src/components/DataTableCells/AccountsListFieldCell.js index 4757d6e01..c5c2a6dcc 100644 --- a/client/src/components/DataTableCells/AccountsListFieldCell.js +++ b/client/src/components/DataTableCells/AccountsListFieldCell.js @@ -1,5 +1,6 @@ import React, { useCallback, useMemo } from 'react'; -import AccountsSelectList from 'components/AccountsSelectList'; +import AccountsSuggestField from 'components/AccountsSuggestField'; +// import AccountsSelectList from 'components/AccountsSelectList'; import classNames from 'classnames'; import { FormGroup, Classes, Intent } from '@blueprintjs/core'; @@ -42,7 +43,7 @@ const AccountCellRenderer = ({ Classes.FILL, )} > -