diff --git a/client/src/components/AccountsSuggestField.js b/client/src/components/AccountsSuggestField.js
new file mode 100644
index 000000000..c0757d8b0
--- /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 }}
+ inputValueRenderer={handleInputValueRenderer}
+ className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
+ [CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
+ })}
+ {...suggestProps}
+ />
+ );
+}
diff --git a/client/src/components/ContactsSuggestField.js b/client/src/components/ContactsSuggestField.js
new file mode 100644
index 000000000..4269d21ff
--- /dev/null
+++ b/client/src/components/ContactsSuggestField.js
@@ -0,0 +1,106 @@
+import React, { useCallback, useState, useEffect, useMemo } from 'react';
+import { MenuItem } from '@blueprintjs/core';
+import { Suggest } from '@blueprintjs/select';
+
+import { FormattedMessage as T } from 'react-intl';
+import classNames from 'classnames';
+import { CLASSES } from 'common/classes';
+
+export default function ContactsSuggestField({
+ contactsList,
+ initialContactId,
+ selectedContactId,
+ defaultTextSelect = 'Select contact',
+ onContactSelected,
+
+ selectedContactType = [],
+ popoverFill = false,
+
+ ...suggestProps
+}) {
+ // filteredContacts
+ const contacts = useMemo(
+ () =>
+ contactsList.map((contact) => ({
+ ...contact,
+ _id: `${contact.id}_${contact.contact_type}`,
+ })),
+ [contactsList],
+ );
+
+ const initialContact = useMemo(
+ () => contacts.find((a) => a.id === initialContactId),
+ [initialContactId, contacts],
+ );
+
+ const [selecetedContact, setSelectedContact] = useState(
+ initialContact || null,
+ );
+
+ useEffect(() => {
+ if (typeof selectedContactId !== 'undefined') {
+ const contact = selectedContactId
+ ? contacts.find((a) => a.id === selectedContactId)
+ : null;
+ setSelectedContact(contact);
+ }
+ }, [selectedContactId, contacts, setSelectedContact]);
+
+ const contactRenderer = useCallback(
+ (contact, { handleClick }) => (
+
+ ),
+ [],
+ );
+
+ const onContactSelect = useCallback(
+ (contact) => {
+ setSelectedContact({ ...contact });
+ onContactSelected && onContactSelected(contact);
+ },
+ [setSelectedContact, onContactSelected],
+ );
+
+ const handleInputValueRenderer = (inputValue) => {
+ if (inputValue) {
+ return inputValue.display_name.toString();
+ }
+ };
+
+ const filterContacts = (query, contact, index, exactMatch) => {
+ const normalizedTitle = contact.display_name.toLowerCase();
+ const normalizedQuery = query.toLowerCase();
+ if (exactMatch) {
+ return normalizedTitle === normalizedQuery;
+ } else {
+ return (
+ `${contact.display_name} ${normalizedTitle}`.indexOf(normalizedQuery) >=
+ 0
+ );
+ }
+ };
+
+ return (
+ } />}
+ itemRenderer={contactRenderer}
+ itemPredicate={filterContacts}
+ onItemSelect={onContactSelect}
+ selectedItem={selecetedContact}
+ inputProps={{ placeholder: defaultTextSelect }}
+ resetOnClose={true}
+ // fill={true}
+ popoverProps={{ minimal: true }}
+ inputValueRenderer={handleInputValueRenderer}
+ className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
+ [CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
+ })}
+ {...suggestProps}
+ />
+ );
+}
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,
)}
>
-
-
- {
+ let filteredItems = [...items];
+
+ if (sellable) {
+ filteredItems = filteredItems.filter((item) => item.sellable);
+ }
+ if (purchasable) {
+ filteredItems = filteredItems.filter((item) => item.purchasable);
+ }
+ return filteredItems;
+ }, [items, sellable, purchasable]);
+
+ // Find initial item object.
+ const initialItem = useMemo(
+ () => filteredItems.some((a) => a.id === initialItemId),
+ [initialItemId],
+ );
+
+ const [selectedItem, setSelectedItem] = useState(initialItem || null);
+
+ const onItemSelect = useCallback(
+ (item) => {
+ setSelectedItem({ ...item });
+ onItemSelected && onItemSelected(item);
+ },
+ [setSelectedItem, onItemSelected],
+ );
+
+ const itemRenderer = useCallback((item, { modifiers, handleClick }) => (
+
+ ));
+
+ useEffect(() => {
+ if (typeof selectedItemId !== 'undefined') {
+ const item = selectedItemId
+ ? filteredItems.find((a) => a.id === selectedItemId)
+ : null;
+ setSelectedItem(item);
+ }
+ }, [selectedItemId, filteredItems, setSelectedItem]);
+
+ const handleInputValueRenderer = (inputValue) => {
+ if (inputValue) {
+ return inputValue.name.toString();
+ }
+ return '';
+ };
+
+ // Filters items.
+ const filterItemsPredicater = useCallback(
+ (query, item, _index, exactMatch) => {
+ const normalizedTitle = item.name.toLowerCase();
+ const normalizedQuery = query.toLowerCase();
+
+ if (exactMatch) {
+ return normalizedTitle === normalizedQuery;
+ } else {
+ return normalizedTitle.indexOf(normalizedQuery) >= 0;
+ }
+ },
+ [],
+ );
+ return (
+ } />}
+ itemRenderer={itemRenderer}
+ itemPredicate={filterItemsPredicater}
+ inputValueRenderer={handleInputValueRenderer}
+ selectedItem={selectedItem}
+ onItemSelect={onItemSelect}
+ inputProps={{ placeholder: defautlSelectText }}
+ resetOnClose={true}
+ fill={true}
+ popoverProps={{ minimal: true }}
+ className={classNames(CLASSES.FORM_GROUP_LIST_SELECT, {
+ [CLASSES.SELECT_LIST_FILL_POPOVER]: popoverFill,
+ })}
+ {...suggestProps}
+ />
+ );
+}
diff --git a/client/src/containers/Sales/PaymentReceive/PaymentReceiveList.js b/client/src/containers/Sales/PaymentReceive/PaymentReceiveList.js
index 8b3d36a88..8161a7db0 100644
--- a/client/src/containers/Sales/PaymentReceive/PaymentReceiveList.js
+++ b/client/src/containers/Sales/PaymentReceive/PaymentReceiveList.js
@@ -87,7 +87,7 @@ function PaymentReceiveList({
}, [deletePaymentReceive, requestDeletePaymentReceive, formatMessage]);
const handleEditPaymentReceive = useCallback((payment) => {
- history.push(`/payment-receive/${payment.id}/edit`);
+ history.push(`/payment-receives/${payment.id}/edit`);
});
// Calculates the selected rows count.
diff --git a/client/src/lang/en/index.js b/client/src/lang/en/index.js
index 170c86a2e..a7ecf2ddc 100644
--- a/client/src/lang/en/index.js
+++ b/client/src/lang/en/index.js
@@ -935,4 +935,5 @@ export default {
opening_average_cost: 'Opening average cost',
opening_cost_: 'Opening cost ',
opening_date_: 'Opening date ',
+ no_results:'No results.'
};