From 53cc8ba057e6b5f69284909781875a0d234c89fc Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 21 Jun 2020 19:23:12 +0200 Subject: [PATCH] feat: Context menu on data-table. --- client/src/components/DataTable.js | 17 +- .../Accounting/ManualJournalsDataTable.js | 16 +- .../containers/Accounts/AccountsDataTable.js | 289 ++++++++++-------- .../containers/Expenses/ExpenseDataTable.js | 16 +- .../containers/Items/ItemCategoriesTable.js | 16 +- client/src/containers/Items/ItemsDataTable.js | 199 ++++++------ client/src/lang/en/index.js | 1 + client/src/style/components/data-table.scss | 5 +- .../src/style/pages/financial-statements.scss | 1 - 9 files changed, 337 insertions(+), 223 deletions(-) diff --git a/client/src/components/DataTable.js b/client/src/components/DataTable.js index 7c26f36dd..e0eeadb6a 100644 --- a/client/src/components/DataTable.js +++ b/client/src/components/DataTable.js @@ -8,7 +8,7 @@ import { useSortBy, useFlexLayout, } from 'react-table'; -import { Checkbox, Spinner } from '@blueprintjs/core'; +import { Checkbox, Spinner, ContextMenu, Menu, MenuItem } from '@blueprintjs/core'; import classnames from 'classnames'; import { FixedSizeList } from 'react-window'; import { useSticky } from 'react-table-sticky'; @@ -51,6 +51,7 @@ export default function DataTable({ pagesCount: controlledPageCount, initialPageIndex, initialPageSize, + rowContextMenu }) { const { getTableProps, @@ -192,6 +193,20 @@ export default function DataTable({ [expandable, expandToggleColumn], ); + const handleRowContextMenu = (cell, row) => (e) => { + if (typeof rowContextMenu === 'function') { + e.preventDefault(); + const tr = e.currentTarget.closest('.tr'); + tr.classList.add('is-context-menu-active'); + + const DropdownEl = rowContextMenu(cell, row); + + ContextMenu.show(DropdownEl, { left: e.clientX, top: e.clientY }, () => { + tr.classList.remove('is-context-menu-active'); + }); + } + }; + // Renders table row. const RenderRow = useCallback( ({ style = {}, row }) => { diff --git a/client/src/containers/Accounting/ManualJournalsDataTable.js b/client/src/containers/Accounting/ManualJournalsDataTable.js index ef41f1a16..1ed5c8ce4 100644 --- a/client/src/containers/Accounting/ManualJournalsDataTable.js +++ b/client/src/containers/Accounting/ManualJournalsDataTable.js @@ -102,28 +102,32 @@ function ManualJournalsDataTable({ const actionMenuList = useCallback( (journal) => ( - } /> + {!journal.status && ( } + text={formatMessage({ id: 'publish_journal' })} onClick={handlePublishJournal(journal)} /> )} } + text={formatMessage({ id: 'edit_journal' })} onClick={handleEditJournal(journal)} /> } + text={formatMessage({ id: 'delete_journal' })} intent={Intent.DANGER} onClick={handleDeleteJournal(journal)} /> ), - [handleEditJournal, handleDeleteJournal, handlePublishJournal], + [handleEditJournal, handleDeleteJournal, handlePublishJournal, formatMessage], ); + const onRowContextMenu = useCallback((cell) => { + return actionMenuList(cell.row.original); + }, [actionMenuList]); + const columns = useMemo( () => [ { @@ -245,6 +249,8 @@ function ManualJournalsDataTable({ onSelectedRowsChange={handleSelectedRowsChange} pagination={true} + rowContextMenu={onRowContextMenu} + pagesCount={manualJournalsPagination.pagesCount} initialPageSize={manualJournalsTableQuery.page_size} initialPageIndex={manualJournalsTableQuery.page - 1} diff --git a/client/src/containers/Accounts/AccountsDataTable.js b/client/src/containers/Accounts/AccountsDataTable.js index f84eefe36..01444ac85 100644 --- a/client/src/containers/Accounts/AccountsDataTable.js +++ b/client/src/containers/Accounts/AccountsDataTable.js @@ -1,4 +1,4 @@ -import React, {useCallback, useState, useMemo } from 'react'; +import React, { useCallback, useState, useMemo } from 'react'; import { Button, Popover, @@ -8,6 +8,7 @@ import { Position, Classes, Tooltip, + Intent, } from '@blueprintjs/core'; import { FormattedMessage as T, useIntl } from 'react-intl'; @@ -26,12 +27,11 @@ import withDialogActions from 'containers/Dialog/withDialogActions'; import { If } from 'components'; - function AccountsDataTable({ - // #withDashboardActions + // #withDashboardActions accounts, accountsLoading, - + // #withDialog. openDialog, @@ -52,136 +52,179 @@ function AccountsDataTable({ } }, [accountsLoading, setInitialMount]); - const handleEditAccount = useCallback((account) => () => { - openDialog('account-form', { action: 'edit', id: account.id }); - }, [openDialog]); + const handleEditAccount = useCallback( + (account) => () => { + openDialog('account-form', { action: 'edit', id: account.id }); + }, + [openDialog], + ); - const handleNewParentAccount = useCallback((account) => { - openDialog('account-form', { action: 'new_child', id: account.id }); - }, [openDialog]); + const handleNewParentAccount = useCallback( + (account) => { + openDialog('account-form', { action: 'new_child', id: account.id }); + }, + [openDialog], + ); - const actionMenuList = useCallback((account) => ( - - } /> - - } - onClick={handleEditAccount(account)} /> - } - onClick={() => handleNewParentAccount(account)} /> - - + const actionMenuList = useCallback( + (account) => ( + + + } - onClick={() => onInactiveAccount(account)} /> - - + text={formatMessage({ id: 'edit_account' })} + onClick={handleEditAccount(account)} + /> } - onClick={() => onActivateAccount(account)} /> - - } - onClick={() => onDeleteAccount(account)} /> - - ), [handleEditAccount, onDeleteAccount, onInactiveAccount,handleNewParentAccount]); + text={formatMessage({ id: 'new_child_account' })} + onClick={() => handleNewParentAccount(account)} + /> + + + onInactiveAccount(account)} + /> + + + onActivateAccount(account)} + /> + + onDeleteAccount(account)} + /> + + ), + [ + handleEditAccount, + onDeleteAccount, + onInactiveAccount, + handleNewParentAccount, + formatMessage, + ], + ); - const columns = useMemo(() => [ - { - id: 'name', - Header: formatMessage({id:'account_name'}), - accessor: row => { - return (row.description) ? - ( { + return actionMenuList(cell.row.original); + }; + + const columns = useMemo( + () => [ + { + id: 'name', + Header: formatMessage({ id: 'account_name' }), + accessor: (row) => { + return row.description ? ( + + {row.name} + + ) : ( + row.name + ); + }, + className: 'account_name', + width: 300, + }, + { + id: 'code', + Header: formatMessage({ id: 'code' }), + accessor: 'code', + className: 'code', + width: 100, + }, + { + id: 'type', + Header: formatMessage({ id: 'type' }), + accessor: 'type.name', + className: 'type', + width: 120, + }, + { + id: 'normal', + Header: formatMessage({ id: 'normal' }), + Cell: ({ cell }) => { + const account = cell.row.original; + const normal = account.type ? account.type.normal : ''; + const arrowDirection = normal === 'credit' ? 'down' : 'up'; + + return ( + + + + ); + }, + className: 'normal', + width: 75, + }, + { + id: 'balance', + Header: formatMessage({ id: 'balance' }), + Cell: ({ cell }) => { + const account = cell.row.original; + const { balance = null } = account; + + return balance ? ( + + + + ) : ( + -- + ); + }, + width: 150, + }, + { + id: 'actions', + Header: '', + Cell: ({ cell }) => ( + - { row.name } - ) : row.name; + > +