feat: fix accounts issue.

This commit is contained in:
Ahmed Bouhuolia
2020-06-25 13:43:47 +02:00
parent 6074134a53
commit 111aa83908
46 changed files with 797 additions and 345 deletions

View File

@@ -10,11 +10,12 @@ import {
Popover,
PopoverInteractionKind,
Position,
Intent
Intent,
} from '@blueprintjs/core';
import classNames from 'classnames';
import { useRouteMatch, useHistory } from 'react-router-dom';
import { FormattedMessage as T } from 'react-intl';
import { connect } from 'react-redux';
import FilterDropdown from 'components/FilterDropdown';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
@@ -28,11 +29,9 @@ import withManualJournalsActions from 'containers/Accounting/withManualJournalsA
import { compose } from 'utils';
function ManualJournalActionsBar({
// #withResourceDetail
resourceName = 'manual_journal',
resourceName = 'manual_journals',
resourceFields,
// #withManualJournals
@@ -43,12 +42,12 @@ function ManualJournalActionsBar({
onFilterChanged,
selectedRows,
onBulkDelete
onBulkDelete,
}) {
const { path } = useRouteMatch();
const history = useHistory();
const viewsMenuItems = manualJournalsViews.map(view => {
const viewsMenuItems = manualJournalsViews.map((view) => {
return (
<MenuItem href={`${path}/${view.id}/custom_view`} text={view.name} />
);
@@ -60,18 +59,25 @@ function ManualJournalActionsBar({
const filterDropdown = FilterDropdown({
fields: resourceFields,
onFilterChange: filterConditions => {
initialCondition: {
fieldKey: 'journal_number',
compatator: 'contains',
value: '',
},
onFilterChange: (filterConditions) => {
addManualJournalsTableQueries({
filter_roles: filterConditions || ''
filter_roles: filterConditions || '',
});
onFilterChanged && onFilterChanged(filterConditions);
}
},
});
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [selectedRows]);
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
selectedRows,
]);
// Handle delete button click.
const handleBulkDelete = useCallback(() => {
onBulkDelete && onBulkDelete(selectedRows.map(r => r.id));
onBulkDelete && onBulkDelete(selectedRows.map((r) => r.id));
}, [onBulkDelete, selectedRows]);
return (
@@ -85,8 +91,8 @@ function ManualJournalActionsBar({
>
<Button
className={classNames(Classes.MINIMAL, 'button--table-views')}
icon={<Icon icon='table-16' iconSize={16} />}
text={<T id={'table_views'}/>}
icon={<Icon icon="table-16" iconSize={16} />}
text={<T id={'table_views'} />}
rightIcon={'caret-down'}
/>
</Popover>
@@ -95,27 +101,28 @@ function ManualJournalActionsBar({
<Button
className={Classes.MINIMAL}
icon={<Icon icon='plus' />}
text={<T id={'new_journal'}/>}
icon={<Icon icon="plus" />}
text={<T id={'new_journal'} />}
onClick={onClickNewManualJournal}
/>
<Popover
minimal={true}
content={filterDropdown}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text='Filter'
icon={<Icon icon='filter-16' iconSize={16} />}
text="Filter"
icon={<Icon icon="filter-16" iconSize={16} />}
/>
</Popover>
<If condition={hasSelectedRows}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon='trash-16' iconSize={16} />}
text={<T id={'delete'}/>}
icon={<Icon icon="trash-16" iconSize={16} />}
text={<T id={'delete'} />}
intent={Intent.DANGER}
onClick={handleBulkDelete}
/>
@@ -123,20 +130,27 @@ function ManualJournalActionsBar({
<Button
className={Classes.MINIMAL}
icon={<Icon icon='file-import-16' iconSize={16} />}
text={<T id={'import'}/>}
icon={<Icon icon="file-import-16" iconSize={16} />}
text={<T id={'import'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon='file-export-16' iconSize={16} />}
text={<T id={'export'}/>}
icon={<Icon icon="file-export-16" iconSize={16} />}
text={<T id={'export'} />}
/>
</NavbarGroup>
</DashboardActionsBar>
);
}
const mapStateToProps = (state, props) => ({
resourceName: 'manual_journals',
});
const withManualJournalsActionsBar = connect(mapStateToProps);
export default compose(
withManualJournalsActionsBar,
withDialogActions,
withResourceDetail(({ resourceFields }) => ({
resourceFields,

View File

@@ -17,6 +17,7 @@ import withManualJournals from 'containers/Accounting/withManualJournals';
import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions';
import withViewsActions from 'containers/Views/withViewsActions';
import withRouteActions from 'containers/Router/withRouteActions';
import withResourceActions from 'containers/Resources/withResourcesActions';
import { compose } from 'utils';
@@ -30,6 +31,9 @@ function ManualJournalsTable({
// #withViewsActions
requestFetchResourceViews,
// #withResourceActions
requestFetchResourceFields,
// #withManualJournals
manualJournalsTableQuery,
@@ -50,10 +54,15 @@ function ManualJournalsTable({
const { formatMessage } = useIntl();
const fetchViews = useQuery('journals-resource-views', () => {
const fetchViews = useQuery('manual-journals-resource-views', () => {
return requestFetchResourceViews('manual_journals');
});
const fetchResourceFields = useQuery(
'manual-journals-resource-fields',
() => requestFetchResourceFields('manual_journals'),
);
const fetchManualJournals = useQuery(
['manual-journals-table', manualJournalsTableQuery],
(key, q) => requestFetchManualJournalsTable(q),
@@ -108,8 +117,8 @@ function ManualJournalsTable({
.then(() => {
AppToaster.show({
message: formatMessage(
{ id: 'the_journals_has_been_successfully_deleted', },
{ count: selectedRowsCount, },
{ id: 'the_journals_has_been_successfully_deleted' },
{ count: selectedRowsCount },
),
intent: Intent.SUCCESS,
});
@@ -189,7 +198,7 @@ function ManualJournalsTable({
return (
<DashboardInsider
loading={fetchViews.isFetching}
loading={fetchViews.isFetching || fetchResourceFields.isFetching}
name={'manual-journals'}
>
<ManualJournalsActionsBar
@@ -265,6 +274,7 @@ export default compose(
withDashboardActions,
withManualJournalsActions,
withViewsActions,
withResourceActions,
withManualJournals(({ manualJournalsTableQuery }) => ({
manualJournalsTableQuery,
})),

View File

@@ -28,7 +28,7 @@ export default (mapState) => {
manualJournalsTableQuery.page,
),
manualJournalsTableQuery,
manualJournalsViews: getResourceViews(state, 'manual_journals'),
manualJournalsViews: getResourceViews(state, props, 'manual_journals'),
manualJournalsItems: state.manualJournals.items,
manualJournalsPagination: state.manualJournals.paginationMeta,

View File

@@ -64,6 +64,11 @@ function AccountsActionsBar({
const filterDropdown = FilterDropdown({
fields: resourceFields,
initialCondition: {
fieldKey: 'name',
compatator: 'contains',
value: '',
},
onFilterChange: (filterConditions) => {
setFilterCount(filterConditions.length || 0);
addAccountsTableQueries({
@@ -125,7 +130,7 @@ function AccountsActionsBar({
filterCount <= 0 ? (
<T id={'filter'} />
) : (
`${filterCount} filters applied`
<T id={'count_filters_applied'} values={{ count: filterCount }} />
)
}
icon={<Icon icon="filter-16" iconSize={16} />}

View File

@@ -333,6 +333,7 @@ function AccountsChart({
<AccountsViewsTabs onViewChanged={handleViewChanged} />
<AccountsDataTable
loading={fetchAccountsHook.isFetching}
onDeleteAccount={handleDeleteAccount}
onInactiveAccount={handleInactiveAccount}
onActivateAccount={handleActivateAccount}

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useState, useMemo } from 'react';
import React, { useCallback, useState, useMemo, useEffect } from 'react';
import {
Button,
Popover,
@@ -10,6 +10,7 @@ import {
Tooltip,
Intent,
} from '@blueprintjs/core';
import { withRouter } from 'react-router';
import { FormattedMessage as T, useIntl } from 'react-intl';
import Icon from 'components/Icon';
@@ -24,6 +25,7 @@ import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withAccountsActions from 'containers/Accounts/withAccountsActions';
import withAccounts from 'containers/Accounts/withAccounts';
import withDialogActions from 'containers/Dialog/withDialogActions';
import withCurrentView from 'containers/Views/withCurrentView';
import { If } from 'components';
@@ -35,6 +37,8 @@ function AccountsDataTable({
// #withDialog.
openDialog,
currentViewId,
// own properties
loading,
onFetchData,
@@ -43,14 +47,18 @@ function AccountsDataTable({
onInactiveAccount,
onActivateAccount,
}) {
const [initialMount, setInitialMount] = useState(false);
const [isMounted, setIsMounted] = useState(false);
const { formatMessage } = useIntl();
useEffect(() => {
setIsMounted(false);
}, [currentViewId]);
useUpdateEffect(() => {
if (!accountsLoading) {
setInitialMount(true);
setIsMounted(true);
}
}, [accountsLoading, setInitialMount]);
}, [accountsLoading, setIsMounted]);
const handleEditAccount = useCallback(
(account) => () => {
@@ -132,21 +140,21 @@ function AccountsDataTable({
);
},
className: 'account_name',
width: 300,
width: 220,
},
{
id: 'code',
Header: formatMessage({ id: 'code' }),
accessor: 'code',
className: 'code',
width: 100,
width: 125,
},
{
id: 'type',
Header: formatMessage({ id: 'type' }),
accessor: 'type.name',
className: 'type',
width: 120,
width: 140,
},
{
id: 'normal',
@@ -168,7 +176,7 @@ function AccountsDataTable({
);
},
className: 'normal',
width: 75,
width: 115,
},
{
id: 'balance',
@@ -207,9 +215,9 @@ function AccountsDataTable({
const selectionColumn = useMemo(
() => ({
minWidth: 50,
width: 50,
maxWidth: 50,
minWidth: 40,
width: 40,
maxWidth: 40,
}),
[],
);
@@ -227,7 +235,7 @@ function AccountsDataTable({
);
return (
<LoadingIndicator loading={loading} mount={false}>
<LoadingIndicator loading={loading && !isMounted} mount={false}>
<DataTable
noInitialFetch={true}
columns={columns}
@@ -239,7 +247,7 @@ function AccountsDataTable({
treeGraph={true}
sticky={true}
onSelectedRowsChange={handleSelectedRowsChange}
loading={accountsLoading && !initialMount}
loading={accountsLoading && !isMounted}
spinnerProps={{ size: 30 }}
rowContextMenu={rowContextMenu}
/>
@@ -248,6 +256,8 @@ function AccountsDataTable({
}
export default compose(
withRouter,
withCurrentView,
withDialogActions,
withDashboardActions,
withAccountsActions,

View File

@@ -1,4 +1,4 @@
import React, {useEffect} from 'react';
import React, { useEffect, useRef } from 'react';
import { useHistory } from 'react-router';
import { connect } from 'react-redux';
import {
@@ -7,14 +7,15 @@ import {
NavbarGroup,
Tabs,
Tab,
Button
Button,
} from '@blueprintjs/core';
import { useParams, withRouter } from 'react-router-dom';
import Icon from 'components/Icon';
import { Link } from 'react-router-dom';
import { pick, debounce } from 'lodash';
import Icon from 'components/Icon';
import { FormattedMessage as T } from 'react-intl';
import {useUpdateEffect} from 'hooks';
import { useUpdateEffect } from 'hooks';
import { DashboardViewsTabs } from 'components';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withAccounts from 'containers/Accounts/withAccounts';
import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions';
@@ -48,7 +49,7 @@ function AccountsViewsTabs({
useEffect(() => {
changeAccountsCurrentView(customViewId || -1);
setTopbarEditView(customViewId);
changePageSubtitle((customViewId && viewItem) ? viewItem.name : '');
changePageSubtitle(customViewId && viewItem ? viewItem.name : '');
addAccountsTableQueries({
custom_view_id: customViewId,
@@ -57,7 +58,7 @@ function AccountsViewsTabs({
return () => {
setTopbarEditView(null);
changePageSubtitle('');
changeAccountsCurrentView(null)
changeAccountsCurrentView(null);
};
}, [customViewId]);
@@ -71,52 +72,37 @@ function AccountsViewsTabs({
history.push('/custom_views/accounts/new');
};
// Handle view tab link click.
const handleViewLinkClick = () => {
setTopbarEditView(customViewId);
const tabs = accountsViews.map((view) => ({
...pick(view, ['name', 'id']),
}));
const debounceChangeHistory = useRef(
debounce((toUrl) => {
history.push(toUrl);
}, 250),
);
const handleTabsChange = (viewId) => {
const toPath = viewId ? `${viewId}/custom_view` : '';
debounceChangeHistory.current(`/accounts/${toPath}`);
setTopbarEditView(viewId);
};
const tabs = accountsViews.map((view) => {
const baseUrl = '/accounts';
const link = (
<Link
to={`${baseUrl}/${view.id}/custom_view`}
onClick={handleViewLinkClick}
>{ view.name }</Link>
);
return <Tab id={`custom_view_${view.id}`} title={link} />;
});
return (
<Navbar className='navbar--dashboard-views'>
<Navbar className="navbar--dashboard-views">
<NavbarGroup align={Alignment.LEFT}>
<Tabs
id='navbar'
large={true}
selectedTabId={customViewId ? `custom_view_${customViewId}` : 'all'}
className='tabs--dashboard-views'
>
<Tab
id={'all'}
title={<Link to={`/accounts`}><T id={'all'}/></Link>}
onClick={handleViewLinkClick}
/>
{ tabs }
<Button
className='button--new-view'
icon={<Icon icon='plus' />}
onClick={handleClickNewView}
minimal={true}
/>
</Tabs>
<DashboardViewsTabs
baseUrl={'/accounts'}
tabs={tabs}
onNewViewTabClick={handleClickNewView}
onChange={handleTabsChange}
/>
</NavbarGroup>
</Navbar>
);
}
const mapStateToProps = (state, ownProps) => ({
// Mapping view id from matched route params.
viewId: ownProps.match.params.custom_view_id,
});
@@ -130,5 +116,5 @@ export default compose(
accountsViews,
})),
withAccountsTableActions,
withViewDetail
withViewDetail,
)(AccountsViewsTabs);

View File

@@ -10,8 +10,8 @@ import {
export default (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
accountsViews: getResourceViews(state, 'accounts'),
accounts: getAccountsItems(state, state.accounts.currentViewId),
accountsViews: getResourceViews(state, props, 'accounts'),
accounts: getAccountsItems(state, props),
accountsTypes: state.accounts.accountsTypes,
accountsTableQuery: state.accounts.tableQuery,

View File

@@ -1,10 +1,11 @@
import { connect } from 'react-redux';
import { getCurrenciesList } from 'store/currencies/currencies.selector';
export default (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
currencies: state.currencies.data,
currenciesList: Object.values(state.currencies.data),
currenciesList: getCurrenciesList(state, props),
currenciesLoading: state.currencies.loading,
};
return mapState ? mapState(mapped, state, props) : mapped;

View File

@@ -6,7 +6,7 @@ export default (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
customersViews: getResourceViews(state, 'customers'),
customersViews: getResourceViews(state, props, 'customers'),
customersItems: Object.values(state.customers.items),
customers: getCustomersItems(state, state.customers.currentViewId),
customersLoading: state.customers.loading,

View File

@@ -6,7 +6,7 @@ export default (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
expenses: getExpensesItems(state, state.expenses.currentViewId),
expensesViews: getResourceViews(state, 'expenses'),
expensesViews: getResourceViews(state, props, 'expenses'),
expensesItems: state.expenses.items,
expensesTableQuery: state.expenses.tableQuery,
expensesLoading: state.expenses.loading,

View File

@@ -11,7 +11,7 @@ export default (mapState) => {
const mapStateToProps = (state, props) => {
const viewPages = getViewPages(state.items.views, state.items.currentViewId);
const mapped = {
itemsViews: getResourceViews(state, 'items'),
itemsViews: getResourceViews(state, props, 'items'),
itemsCurrentPage: getCurrentPageResults(
state.items.items,
viewPages,

View File

@@ -11,7 +11,7 @@ export default (mapState) => {
const { resourceName } = props;
const mapped = {
resourceData: getResourceData(state, resourceName),
resourceFields: getResourceFields(state, resourceName),
resourceFields: getResourceFields(state, props),
resourceColumns: getResourceColumns(state, resourceName),
resourceMetadata: getResourceMetadata(state, resourceName),
};

View File

@@ -0,0 +1,7 @@
import { connect } from 'react-redux';
const mapStateToProps = (state, props) => ({
currentViewId: props.match.params.custom_view_id,
});
export default connect(mapStateToProps);

View File

@@ -6,11 +6,9 @@ import {
export const mapStateToProps = (state, props) => {
const { viewId } = props;
return {
viewMeta: getViewMeta(state, viewId),
viewItem: getViewItem(state, viewId),
viewMeta: getViewMeta(state, props),
viewItem: getViewItem(state, props),
};
};