mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
feat: optimize accounts performance.
feat: optimize alerts architecture. feat: optimize datatable architecture. feat: optimize datatable style.
This commit is contained in:
@@ -137,7 +137,8 @@ function ManualJournalsDataTable({
|
||||
accessor: (r) => (
|
||||
<Tooltip
|
||||
content={<AmountPopoverContent journalEntries={r.entries} />}
|
||||
position={Position.RIGHT_BOTTOM}
|
||||
position={Position.RIGHT_TOP}
|
||||
boundary={'viewport'}
|
||||
>
|
||||
<Money amount={r.amount} currency={'USD'} />
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import React, { memo, useState } from 'react';
|
||||
import Icon from 'components/Icon';
|
||||
import {
|
||||
Button,
|
||||
@@ -22,9 +22,13 @@ import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
import withResourceDetail from 'containers/Resources/withResourceDetails';
|
||||
import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions';
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Accounts actions bar.
|
||||
*/
|
||||
function AccountsActionsBar({
|
||||
openDialog,
|
||||
accountsViews,
|
||||
@@ -32,18 +36,18 @@ function AccountsActionsBar({
|
||||
// #withResourceDetail
|
||||
resourceFields,
|
||||
|
||||
// #withAccountsActions
|
||||
// #withAccountsTableActions
|
||||
addAccountsTableQueries,
|
||||
setAccountsBulkAction,
|
||||
|
||||
// #withAccounts
|
||||
accountsTableQuery,
|
||||
accountsSelectedRows,
|
||||
|
||||
// #withAlertActions
|
||||
openAlert,
|
||||
|
||||
selectedRows = [],
|
||||
onFilterChanged,
|
||||
onBulkDelete,
|
||||
onBulkArchive,
|
||||
onBulkActivate,
|
||||
onBulkInactive,
|
||||
}) {
|
||||
const [filterCount, setFilterCount] = useState(
|
||||
accountsTableQuery?.filter_roles?.length || 0,
|
||||
@@ -53,10 +57,7 @@ function AccountsActionsBar({
|
||||
openDialog('account-form', {});
|
||||
};
|
||||
|
||||
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
|
||||
selectedRows,
|
||||
]);
|
||||
|
||||
// Filter dropdown.
|
||||
const filterDropdown = FilterDropdown({
|
||||
fields: resourceFields,
|
||||
initialConditions: accountsTableQuery.filter_roles,
|
||||
@@ -74,17 +75,17 @@ function AccountsActionsBar({
|
||||
},
|
||||
});
|
||||
|
||||
const handleBulkDelete = useCallback(() => {
|
||||
onBulkDelete && onBulkDelete(selectedRows.map((r) => r.id));
|
||||
}, [onBulkDelete, selectedRows]);
|
||||
const handleBulkDelete = () => {
|
||||
openAlert('accounts-bulk-delete', { accountsIds: accountsSelectedRows });
|
||||
};
|
||||
|
||||
const handelBulkActivate = useCallback(() => {
|
||||
onBulkActivate && onBulkActivate(selectedRows.map((r) => r.id));
|
||||
}, [onBulkActivate, selectedRows]);
|
||||
const handelBulkActivate = () => {
|
||||
openAlert('accounts-bulk-activate', { accountsIds: accountsSelectedRows });
|
||||
};
|
||||
|
||||
const handelBulkInactive = useCallback(() => {
|
||||
onBulkInactive && onBulkInactive(selectedRows.map((r) => r.id));
|
||||
}, [onBulkInactive, selectedRows]);
|
||||
const handelBulkInactive = () => {
|
||||
openAlert('accounts-bulk-inactivate', { accountsIds: accountsSelectedRows });
|
||||
};
|
||||
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
@@ -113,7 +114,7 @@ function AccountsActionsBar({
|
||||
'has-active-filters': filterCount > 0,
|
||||
})}
|
||||
text={
|
||||
filterCount <= 0 ? (
|
||||
(filterCount <= 0) ? (
|
||||
<T id={'filter'} />
|
||||
) : (
|
||||
<T
|
||||
@@ -126,7 +127,7 @@ function AccountsActionsBar({
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
<If condition={hasSelectedRows}>
|
||||
<If condition={accountsSelectedRows.length}>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon={<Icon icon="play-16" iconSize={16} />}
|
||||
@@ -168,21 +169,30 @@ function AccountsActionsBar({
|
||||
);
|
||||
}
|
||||
|
||||
// Momerize the component.
|
||||
const AccountsActionsBarMemo = memo(AccountsActionsBar);
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
resourceName: 'accounts',
|
||||
});
|
||||
|
||||
const withAccountsActionsBar = connect(mapStateToProps);
|
||||
|
||||
export default compose(
|
||||
const comp = compose(
|
||||
withAccountsActionsBar,
|
||||
withDialogActions,
|
||||
withAccounts(({ accountsViews, accountsTableQuery }) => ({
|
||||
accountsViews,
|
||||
accountsTableQuery,
|
||||
})),
|
||||
withAccounts(
|
||||
({ accountsSelectedRows, accountsViews, accountsTableQuery }) => ({
|
||||
accountsViews,
|
||||
accountsTableQuery,
|
||||
accountsSelectedRows,
|
||||
}),
|
||||
),
|
||||
withResourceDetail(({ resourceFields }) => ({
|
||||
resourceFields,
|
||||
})),
|
||||
withAccountsTableActions,
|
||||
)(AccountsActionsBar);
|
||||
withAlertActions
|
||||
)(AccountsActionsBarMemo);
|
||||
|
||||
export default comp;
|
||||
|
||||
26
client/src/containers/Accounts/AccountsAlerts.js
Normal file
26
client/src/containers/Accounts/AccountsAlerts.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import AccountDeleteAlert from 'containers/Alerts/AccountDeleteAlert';
|
||||
import AccountInactivateAlert from 'containers/Alerts/AccountInactivateAlert';
|
||||
import AccountActivateAlert from 'containers/Alerts/AccountActivateAlert';
|
||||
import AccountBulkDeleteAlert from 'containers/Alerts/AccountBulkDeleteAlert';
|
||||
import AccountBulkInactivateAlert from 'containers/Alerts/AccountBulkInactivateAlert';
|
||||
import AccountBulkActivateAlert from 'containers/Alerts/AccountBulkActivateAlert';
|
||||
|
||||
/**
|
||||
* Accounts alert.
|
||||
*/
|
||||
export default function AccountsAlerts({
|
||||
|
||||
}) {
|
||||
return (
|
||||
<div class="accounts-alerts">
|
||||
<AccountDeleteAlert name={'account-delete'} />
|
||||
<AccountInactivateAlert name={'account-inactivate'} />
|
||||
<AccountActivateAlert name={'account-activate'} />
|
||||
|
||||
<AccountBulkDeleteAlert name={'accounts-bulk-delete'} />
|
||||
<AccountBulkInactivateAlert name={'accounts-bulk-inactivate'} />
|
||||
<AccountBulkActivateAlert name={'accounts-bulk-activate'} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { Alert, Intent } from '@blueprintjs/core';
|
||||
import { useQuery, queryCache } from 'react-query';
|
||||
import { useQuery } from 'react-query';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
FormattedHTMLMessage,
|
||||
useIntl,
|
||||
} from 'react-intl';
|
||||
|
||||
import AppToaster from 'components/AppToaster';
|
||||
import 'style/pages/Accounts/List.scss';
|
||||
|
||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||
import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
||||
import AccountsViewsTabs from 'containers/Accounts/AccountsViewsTabs';
|
||||
import AccountsDataTable from 'containers/Accounts/AccountsDataTable';
|
||||
import DashboardActionsBar from 'containers/Accounts/AccountsActionsBar';
|
||||
import AccountsViewPage from 'containers/Accounts/AccountsViewPage';
|
||||
import AccountsActionsBar from 'containers/Accounts/AccountsActionsBar';
|
||||
import AccountsAlerts from './AccountsAlerts';
|
||||
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withResourceActions from 'containers/Resources/withResourcesActions';
|
||||
@@ -25,8 +22,6 @@ import withAccounts from 'containers/Accounts/withAccounts';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
import 'style/pages/Accounts/List.scss';
|
||||
|
||||
/**
|
||||
* Accounts chart list.
|
||||
*/
|
||||
@@ -34,11 +29,6 @@ function AccountsChart({
|
||||
// #withDashboardActions
|
||||
changePageTitle,
|
||||
|
||||
// #withAccountsActions
|
||||
requestDeleteAccount,
|
||||
requestInactiveAccount,
|
||||
requestActivateAccount,
|
||||
|
||||
// #withViewsActions
|
||||
requestFetchResourceViews,
|
||||
|
||||
@@ -47,35 +37,23 @@ function AccountsChart({
|
||||
|
||||
// #withAccountsTableActions
|
||||
requestFetchAccountsTable,
|
||||
requestDeleteBulkAccounts,
|
||||
addAccountsTableQueries,
|
||||
requestBulkActivateAccounts,
|
||||
requestBulkInactiveAccounts,
|
||||
|
||||
// #withAccounts
|
||||
accountsTableQuery,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const [deleteAccount, setDeleteAccount] = useState(false);
|
||||
const [inactiveAccount, setInactiveAccount] = useState(false);
|
||||
const [activateAccount, setActivateAccount] = useState(false);
|
||||
const [bulkDelete, setBulkDelete] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
const [bulkActivate, setBulkActivate] = useState(false);
|
||||
const [bulkInactiveAccounts, setBulkInactiveAccounts] = useState(false);
|
||||
|
||||
// Fetch accounts resource views and fields.
|
||||
const fetchResourceViews = useQuery(
|
||||
['resource-views', 'accounts'],
|
||||
(key, resourceName) => requestFetchResourceViews(resourceName),
|
||||
);
|
||||
|
||||
// Fetch the accounts resource fields.
|
||||
const fetchResourceFields = useQuery(
|
||||
['resource-fields', 'accounts'],
|
||||
(key, resourceName) => requestFetchResourceFields(resourceName),
|
||||
);
|
||||
|
||||
// Fetch accounts list according to the given custom view id.
|
||||
const fetchAccountsHook = useQuery(
|
||||
['accounts-table', accountsTableQuery],
|
||||
@@ -86,162 +64,10 @@ function AccountsChart({
|
||||
changePageTitle(formatMessage({ id: 'chart_of_accounts' }));
|
||||
}, [changePageTitle, formatMessage]);
|
||||
|
||||
// Handle click and cancel/confirm account delete
|
||||
const handleDeleteAccount = (account) => {
|
||||
setDeleteAccount(account);
|
||||
};
|
||||
|
||||
// handle cancel delete account alert.
|
||||
const handleCancelAccountDelete = useCallback(() => {
|
||||
setDeleteAccount(false);
|
||||
}, []);
|
||||
|
||||
// Handle delete errors in bulk and singular.
|
||||
const handleDeleteErrors = (errors) => {
|
||||
if (errors.find((e) => e.type === 'ACCOUNT.PREDEFINED')) {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'you_could_not_delete_predefined_accounts',
|
||||
}),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
if (errors.find((e) => e.type === 'ACCOUNT.HAS.ASSOCIATED.TRANSACTIONS')) {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'cannot_delete_account_has_associated_transactions',
|
||||
}),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle confirm account delete
|
||||
const handleConfirmAccountDelete = useCallback(() => {
|
||||
requestDeleteAccount(deleteAccount.id)
|
||||
.then(() => {
|
||||
setDeleteAccount(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_account_has_been_successfully_deleted',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
setDeleteAccount(false);
|
||||
handleDeleteErrors(errors);
|
||||
});
|
||||
}, [deleteAccount, requestDeleteAccount, formatMessage]);
|
||||
|
||||
// Handle cancel/confirm account inactive.
|
||||
const handleInactiveAccount = useCallback((account) => {
|
||||
setInactiveAccount(account);
|
||||
}, []);
|
||||
|
||||
// Handle cancel inactive account alert.
|
||||
const handleCancelInactiveAccount = useCallback(() => {
|
||||
setInactiveAccount(false);
|
||||
}, []);
|
||||
|
||||
// Handle confirm account activation.
|
||||
|
||||
const handleConfirmAccountActive = useCallback(() => {
|
||||
requestInactiveAccount(inactiveAccount.id)
|
||||
.then(() => {
|
||||
setInactiveAccount(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_account_has_been_successfully_inactivated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((error) => {
|
||||
setInactiveAccount(false);
|
||||
});
|
||||
}, [inactiveAccount, requestInactiveAccount, formatMessage]);
|
||||
|
||||
// Handle activate account click.
|
||||
const handleActivateAccount = useCallback((account) => {
|
||||
setActivateAccount(account);
|
||||
});
|
||||
|
||||
// Handle activate account alert cancel.
|
||||
const handleCancelActivateAccount = useCallback(() => {
|
||||
setActivateAccount(false);
|
||||
});
|
||||
|
||||
// Handle activate account confirm.
|
||||
const handleConfirmAccountActivate = useCallback(() => {
|
||||
requestActivateAccount(activateAccount.id)
|
||||
.then(() => {
|
||||
setActivateAccount(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_account_has_been_successfully_activated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((error) => {
|
||||
setActivateAccount(false);
|
||||
});
|
||||
}, [activateAccount, requestActivateAccount, formatMessage]);
|
||||
|
||||
const handleRestoreAccount = (account) => {};
|
||||
|
||||
// Handle accounts bulk delete button click.,
|
||||
const handleBulkDelete = useCallback(
|
||||
(accountsIds) => {
|
||||
setBulkDelete(accountsIds);
|
||||
},
|
||||
[setBulkDelete],
|
||||
);
|
||||
|
||||
// Handle confirm accounts bulk delete.
|
||||
const handleConfirmBulkDelete = useCallback(() => {
|
||||
requestDeleteBulkAccounts(bulkDelete)
|
||||
.then(() => {
|
||||
setBulkDelete(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_accounts_has_been_successfully_deleted',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
setBulkDelete(false);
|
||||
handleDeleteErrors(errors);
|
||||
});
|
||||
}, [requestDeleteBulkAccounts, bulkDelete, formatMessage]);
|
||||
|
||||
// Handle cancel accounts bulk delete.
|
||||
const handleCancelBulkDelete = useCallback(() => {
|
||||
setBulkDelete(false);
|
||||
}, []);
|
||||
|
||||
const handleBulkArchive = useCallback((accounts) => {}, []);
|
||||
|
||||
const handleEditAccount = useCallback(() => {}, []);
|
||||
|
||||
// Handle selected rows change.
|
||||
const handleSelectedRowsChange = useCallback(
|
||||
(accounts) => {
|
||||
setSelectedRows(accounts);
|
||||
},
|
||||
[setSelectedRows],
|
||||
);
|
||||
|
||||
// Refetches accounts data table when current custom view changed.
|
||||
const handleFilterChanged = useCallback(() => {
|
||||
fetchAccountsHook.refetch();
|
||||
}, [fetchAccountsHook]);
|
||||
|
||||
}, []);
|
||||
|
||||
// Handle fetch data of accounts datatable.
|
||||
const handleFetchData = useCallback(
|
||||
@@ -255,198 +81,22 @@ function AccountsChart({
|
||||
: {}),
|
||||
});
|
||||
},
|
||||
[fetchAccountsHook, addAccountsTableQueries],
|
||||
[addAccountsTableQueries],
|
||||
);
|
||||
|
||||
// Calculates the data table selected rows count.
|
||||
const selectedRowsCount = useMemo(() => Object.values(selectedRows).length, [
|
||||
selectedRows,
|
||||
]);
|
||||
|
||||
// Handle bulk Activate accounts button click.,
|
||||
const handleBulkActivate = useCallback(
|
||||
(bulkActivateIds) => {
|
||||
setBulkActivate(bulkActivateIds);
|
||||
},
|
||||
[setBulkActivate],
|
||||
);
|
||||
|
||||
// Handle cancel Bulk Activate accounts bulk delete.
|
||||
const handleCancelBulkActivate = useCallback(() => {
|
||||
setBulkActivate(false);
|
||||
}, []);
|
||||
|
||||
// Handle Bulk activate account confirm.
|
||||
const handleConfirmBulkActivate = useCallback(() => {
|
||||
requestBulkActivateAccounts(bulkActivate)
|
||||
.then(() => {
|
||||
setBulkActivate(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_accounts_has_been_successfully_activated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
setBulkActivate(false);
|
||||
});
|
||||
}, [requestBulkActivateAccounts, bulkActivate, formatMessage]);
|
||||
|
||||
// Handle bulk Inactive accounts button click.,
|
||||
const handleBulkInactive = useCallback(
|
||||
(bulkInactiveIds) => {
|
||||
setBulkInactiveAccounts(bulkInactiveIds);
|
||||
},
|
||||
[setBulkInactiveAccounts],
|
||||
);
|
||||
|
||||
// Handle cancel Bulk Inactive accounts bulk delete.
|
||||
const handleCancelBulkInactive = useCallback(() => {
|
||||
setBulkInactiveAccounts(false);
|
||||
}, []);
|
||||
|
||||
// Handle Bulk Inactive accounts confirm.
|
||||
const handleConfirmBulkInactive = useCallback(() => {
|
||||
requestBulkInactiveAccounts(bulkInactiveAccounts)
|
||||
.then(() => {
|
||||
setBulkInactiveAccounts(false);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_accounts_have_been_successfully_inactivated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
setBulkInactiveAccounts(false);
|
||||
});
|
||||
}, [requestBulkInactiveAccounts, bulkInactiveAccounts]);
|
||||
|
||||
return (
|
||||
<DashboardInsider
|
||||
loading={fetchResourceFields.isFetching || fetchResourceViews.isFetching}
|
||||
name={'accounts-chart'}
|
||||
>
|
||||
<DashboardActionsBar
|
||||
selectedRows={selectedRows}
|
||||
<AccountsActionsBar
|
||||
onFilterChanged={handleFilterChanged}
|
||||
onBulkDelete={handleBulkDelete}
|
||||
onBulkArchive={handleBulkArchive}
|
||||
onBulkActivate={handleBulkActivate}
|
||||
onBulkInactive={handleBulkInactive}
|
||||
/>
|
||||
<DashboardPageContent>
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/accounts/:custom_view_id/custom_view', '/accounts']}
|
||||
>
|
||||
<AccountsViewsTabs />
|
||||
|
||||
<AccountsDataTable
|
||||
onDeleteAccount={handleDeleteAccount}
|
||||
onInactiveAccount={handleInactiveAccount}
|
||||
onActivateAccount={handleActivateAccount}
|
||||
onRestoreAccount={handleRestoreAccount}
|
||||
onEditAccount={handleEditAccount}
|
||||
onFetchData={handleFetchData}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'delete'} />}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={deleteAccount}
|
||||
onCancel={handleCancelAccountDelete}
|
||||
onConfirm={handleConfirmAccountDelete}
|
||||
>
|
||||
<p>
|
||||
<FormattedHTMLMessage
|
||||
id={'once_delete_this_account_you_will_able_to_restore_it'}
|
||||
/>
|
||||
</p>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'inactivate'} />}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={inactiveAccount}
|
||||
onCancel={handleCancelInactiveAccount}
|
||||
onConfirm={handleConfirmAccountActive}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_inactive_this_account'} />
|
||||
</p>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'activate'} />}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={activateAccount}
|
||||
onCancel={handleCancelActivateAccount}
|
||||
onConfirm={handleConfirmAccountActivate}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_activate_this_account'} />
|
||||
</p>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={`${formatMessage({
|
||||
id: 'delete',
|
||||
})} (${selectedRowsCount})`}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={bulkDelete}
|
||||
onCancel={handleCancelBulkDelete}
|
||||
onConfirm={handleConfirmBulkDelete}
|
||||
>
|
||||
<p>
|
||||
<T
|
||||
id={'once_delete_these_accounts_you_will_not_able_restore_them'}
|
||||
/>
|
||||
</p>
|
||||
</Alert>
|
||||
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={`${formatMessage({
|
||||
id: 'activate',
|
||||
})} (${selectedRowsCount})`}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={bulkActivate}
|
||||
onCancel={handleCancelBulkActivate}
|
||||
onConfirm={handleConfirmBulkActivate}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_activate_this_accounts'} />
|
||||
</p>
|
||||
</Alert>
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={`${formatMessage({
|
||||
id: 'inactivate',
|
||||
})} (${selectedRowsCount})`}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={bulkInactiveAccounts}
|
||||
onCancel={handleCancelBulkInactive}
|
||||
onConfirm={handleConfirmBulkInactive}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_inactive_this_accounts'} />
|
||||
</p>
|
||||
</Alert>
|
||||
<AccountsViewPage />
|
||||
</DashboardPageContent>
|
||||
|
||||
<AccountsAlerts />
|
||||
</DashboardInsider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,47 +2,45 @@ import React, { useCallback, useState, useMemo, useEffect } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Popover,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuDivider,
|
||||
Position,
|
||||
Intent,
|
||||
} from '@blueprintjs/core';
|
||||
import { withRouter } from 'react-router';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { Icon, DataTable, If } from 'components';
|
||||
import { compose } from 'utils';
|
||||
import { saveInvoke, compose } from 'utils';
|
||||
import { useUpdateEffect } from 'hooks';
|
||||
|
||||
import { CLASSES } from 'common/classes';
|
||||
import {
|
||||
NormalCell,
|
||||
BalanceCell,
|
||||
} from './components';
|
||||
|
||||
import { NormalCell, BalanceCell, AccountActionsMenuList } from './components';
|
||||
import { TableFastCell } from 'components';
|
||||
import TableVirtualizedListRows from 'components/Datatable/TableVirtualizedRows';
|
||||
|
||||
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';
|
||||
|
||||
/**
|
||||
* Accounts data-table.
|
||||
*/
|
||||
function AccountsDataTable({
|
||||
// #withDashboardActions
|
||||
accountsTable,
|
||||
accountsLoading,
|
||||
|
||||
// #withDialog.
|
||||
openDialog,
|
||||
|
||||
// #
|
||||
currentViewId,
|
||||
|
||||
// own properties
|
||||
// #ownProps
|
||||
onFetchData,
|
||||
onSelectedRowsChange,
|
||||
onDeleteAccount,
|
||||
onInactiveAccount,
|
||||
onInactivateAccount,
|
||||
onActivateAccount,
|
||||
onEditAccount,
|
||||
onNewChildAccount
|
||||
}) {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
const { formatMessage } = useIntl();
|
||||
@@ -57,77 +55,44 @@ function AccountsDataTable({
|
||||
}
|
||||
}, [accountsLoading, setIsMounted]);
|
||||
|
||||
const handleEditAccount = useCallback(
|
||||
(account) => () => {
|
||||
openDialog('account-form', { action: 'edit', id: account.id });
|
||||
},
|
||||
[openDialog],
|
||||
);
|
||||
|
||||
const handleNewParentAccount = useCallback(
|
||||
(account) => {
|
||||
openDialog('account-form', {
|
||||
action: 'new_child',
|
||||
parentAccountId: account.id,
|
||||
accountTypeId: account.account_type_id,
|
||||
});
|
||||
},
|
||||
[openDialog],
|
||||
);
|
||||
const ActionsCell = useMemo(() =>
|
||||
({ row }) => (
|
||||
<Popover
|
||||
content={<AccountActionsMenuList
|
||||
account={row.original}
|
||||
onDeleteAccount={onDeleteAccount}
|
||||
onInactivateAccount={onInactivateAccount}
|
||||
onActivateAccount={onActivateAccount}
|
||||
onEditAccount={onEditAccount}
|
||||
/>}
|
||||
position={Position.RIGHT_TOP}
|
||||
>
|
||||
<Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||
</Popover>
|
||||
), [
|
||||
onDeleteAccount,
|
||||
onInactivateAccount,
|
||||
onActivateAccount,
|
||||
onEditAccount
|
||||
]);
|
||||
|
||||
const actionMenuList = useCallback(
|
||||
(account) => (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={formatMessage({ id: 'view_details' })}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={formatMessage({ id: 'edit_account' })}
|
||||
onClick={handleEditAccount(account)}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={<Icon icon="plus" />}
|
||||
text={formatMessage({ id: 'new_child_account' })}
|
||||
onClick={() => handleNewParentAccount(account)}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<If condition={account.active}>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'inactivate_account' })}
|
||||
icon={<Icon icon="pause-16" iconSize={16} />}
|
||||
onClick={() => onInactiveAccount(account)}
|
||||
/>
|
||||
</If>
|
||||
<If condition={!account.active}>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'activate_account' })}
|
||||
icon={<Icon icon="play-16" iconSize={16} />}
|
||||
onClick={() => onActivateAccount(account)}
|
||||
/>
|
||||
</If>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'delete_account' })}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={() => onDeleteAccount(account)}
|
||||
/>
|
||||
</Menu>
|
||||
),
|
||||
[
|
||||
handleEditAccount,
|
||||
onDeleteAccount,
|
||||
onInactiveAccount,
|
||||
handleNewParentAccount,
|
||||
formatMessage,
|
||||
],
|
||||
);
|
||||
|
||||
const rowContextMenu = (cell) => {
|
||||
return actionMenuList(cell.row.original);
|
||||
};
|
||||
const RowContextMenu = useMemo(() => ({ row }) => (
|
||||
<AccountActionsMenuList
|
||||
account={row.original}
|
||||
onDeleteAccount={onDeleteAccount}
|
||||
onInactivateAccount={onInactivateAccount}
|
||||
onActivateAccount={onActivateAccount}
|
||||
onEditAccount={onEditAccount}
|
||||
onNewChildAccount={onNewChildAccount}
|
||||
/>
|
||||
), [
|
||||
onDeleteAccount,
|
||||
onInactivateAccount,
|
||||
onActivateAccount,
|
||||
onEditAccount,
|
||||
onNewChildAccount
|
||||
]);
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
@@ -143,7 +108,7 @@ function AccountsDataTable({
|
||||
Header: formatMessage({ id: 'code' }),
|
||||
accessor: 'code',
|
||||
className: 'code',
|
||||
width: 70,
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
@@ -158,7 +123,7 @@ function AccountsDataTable({
|
||||
Cell: NormalCell,
|
||||
accessor: 'account_normal',
|
||||
className: 'normal',
|
||||
width: 65,
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
id: 'currency',
|
||||
@@ -176,40 +141,31 @@ function AccountsDataTable({
|
||||
{
|
||||
id: 'actions',
|
||||
Header: '',
|
||||
// Cell: ({ cell }) => (
|
||||
// <Popover
|
||||
// content={actionMenuList(cell.row.original)}
|
||||
// position={Position.RIGHT_TOP}
|
||||
// >
|
||||
// <Button icon={<Icon icon="more-h-16" iconSize={16} />} />
|
||||
// </Popover>
|
||||
// ),
|
||||
Cell: ActionsCell,
|
||||
className: 'actions',
|
||||
width: 50,
|
||||
},
|
||||
],
|
||||
[actionMenuList, formatMessage],
|
||||
[ActionsCell, formatMessage],
|
||||
);
|
||||
|
||||
|
||||
|
||||
const handleDatatableFetchData = useCallback((...params) => {
|
||||
onFetchData && onFetchData(...params);
|
||||
}, []);
|
||||
const handleDatatableFetchData = useCallback(
|
||||
(...params) => {
|
||||
saveInvoke(onFetchData, params);
|
||||
},
|
||||
[onFetchData],
|
||||
);
|
||||
|
||||
const handleSelectedRowsChange = useCallback(
|
||||
(selectedRows) => {
|
||||
onSelectedRowsChange &&
|
||||
onSelectedRowsChange(selectedRows.map((s) => s.original));
|
||||
saveInvoke(onSelectedRowsChange, selectedRows);
|
||||
},
|
||||
[onSelectedRowsChange],
|
||||
);
|
||||
|
||||
const rowClassNames = (row) => {
|
||||
return {
|
||||
'inactive': !row.original.active,
|
||||
};
|
||||
};
|
||||
const rowClassNames = (row) => ({
|
||||
inactive: !row.original.active,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={classNames(CLASSES.DASHBOARD_DATATABLE)}>
|
||||
@@ -223,14 +179,19 @@ function AccountsDataTable({
|
||||
sticky={true}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
loading={accountsLoading && !isMounted}
|
||||
rowContextMenu={rowContextMenu}
|
||||
rowContextMenu={RowContextMenu}
|
||||
rowClassNames={rowClassNames}
|
||||
expandColumnSpace={1}
|
||||
autoResetExpanded={false}
|
||||
autoResetSortBy={false}
|
||||
autoResetSelectedRows={false}
|
||||
expandColumnSpace={1}
|
||||
expandToggleColumn={2}
|
||||
selectionColumnWidth={50}
|
||||
virtualizedRows={true}
|
||||
fixedSizeHeight={1000}
|
||||
TableCellRenderer={TableFastCell}
|
||||
TableRowsRenderer={TableVirtualizedListRows}
|
||||
// #TableVirtualizedListRows props.
|
||||
vListrowHeight={42}
|
||||
vListOverscanRowCount={10}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -239,7 +200,6 @@ function AccountsDataTable({
|
||||
export default compose(
|
||||
withRouter,
|
||||
withCurrentView,
|
||||
withDialogActions,
|
||||
withDashboardActions,
|
||||
withAccountsActions,
|
||||
withAccounts(({ accountsLoading, accountsTable }) => ({
|
||||
|
||||
84
client/src/containers/Accounts/AccountsViewPage.js
Normal file
84
client/src/containers/Accounts/AccountsViewPage.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import React, { memo } from 'react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
import AccountsViewsTabs from 'containers/Accounts/AccountsViewsTabs';
|
||||
import AccountsDataTable from 'containers/Accounts/AccountsDataTable';
|
||||
|
||||
import withAccountsTableActions from 'containers/Accounts/withAccountsTableActions';
|
||||
import withAlertsActions from 'containers/Alert/withAlertActions';
|
||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Accounts view page.
|
||||
*/
|
||||
function AccountsViewPage({
|
||||
openAlert,
|
||||
|
||||
// #withDialog.
|
||||
openDialog,
|
||||
|
||||
// #withAccountsTableActions
|
||||
setSelectedRowsAccounts
|
||||
}) {
|
||||
// Handle delete action account.
|
||||
const handleDeleteAccount = (account) => {
|
||||
openAlert('account-delete', { accountId: account.id })
|
||||
};
|
||||
|
||||
// Handle activate action account.
|
||||
const handleActivateAccount = (account) => {
|
||||
openAlert('account-activate', { accountId: account.id });
|
||||
};
|
||||
|
||||
// Handle inactivate action account.
|
||||
const handleInactivateAccount = (account) => {
|
||||
openAlert('account-inactivate', { accountId: account.id });
|
||||
};
|
||||
|
||||
// Handle select accounts datatable rows.
|
||||
const handleSelectedRowsChange = (selectedRows) => {
|
||||
const selectedRowsIds = selectedRows.map(r => r.id);
|
||||
setSelectedRowsAccounts(selectedRowsIds);
|
||||
};
|
||||
|
||||
const handleEditAccount = (account) => {
|
||||
openDialog('account-form', { action: 'edit', id: account.id });
|
||||
}
|
||||
|
||||
const handleNewChildAccount = (account) => {
|
||||
openDialog('account-form', {
|
||||
action: 'new_child',
|
||||
parentAccountId: account.id,
|
||||
accountType: account.account_type,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
exact={true}
|
||||
path={['/accounts/:custom_view_id/custom_view', '/accounts']}
|
||||
>
|
||||
<AccountsViewsTabs />
|
||||
|
||||
<AccountsDataTable
|
||||
onDeleteAccount={handleDeleteAccount}
|
||||
onInactivateAccount={handleInactivateAccount}
|
||||
onActivateAccount={handleActivateAccount}
|
||||
onSelectedRowsChange={handleSelectedRowsChange}
|
||||
onEditAccount={handleEditAccount}
|
||||
onNewChildAccount={handleNewChildAccount}
|
||||
/>
|
||||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
||||
const AccountsViewPageMemo = memo(AccountsViewPage);
|
||||
|
||||
export default compose(
|
||||
withAlertsActions,
|
||||
withAccountsTableActions,
|
||||
withDialogActions
|
||||
)(AccountsViewPageMemo);
|
||||
@@ -1,11 +1,10 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useMemo, memo, useCallback } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { connect } from 'react-redux';
|
||||
import { Alignment, Navbar, NavbarGroup } from '@blueprintjs/core';
|
||||
import { useParams, withRouter } from 'react-router-dom';
|
||||
import { pick } from 'lodash';
|
||||
|
||||
import { useUpdateEffect } from 'hooks';
|
||||
import { DashboardViewsTabs } from 'components';
|
||||
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
|
||||
import withAccounts from 'containers/Accounts/withAccounts';
|
||||
@@ -14,6 +13,9 @@ import withViewDetail from 'containers/Views/withViewDetails';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Accounts views tabs.
|
||||
*/
|
||||
function AccountsViewsTabs({
|
||||
// #withViewDetail
|
||||
viewId,
|
||||
@@ -23,16 +25,11 @@ function AccountsViewsTabs({
|
||||
accountsViews,
|
||||
|
||||
// #withAccountsTableActions
|
||||
addAccountsTableQueries,
|
||||
changeAccountsCurrentView,
|
||||
|
||||
// #withDashboardActions
|
||||
setTopbarEditView,
|
||||
changePageSubtitle,
|
||||
|
||||
// props
|
||||
customViewChanged,
|
||||
onViewChanged,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { custom_view_id: customViewId = null } = useParams();
|
||||
@@ -40,28 +37,27 @@ function AccountsViewsTabs({
|
||||
useEffect(() => {
|
||||
setTopbarEditView(customViewId);
|
||||
changePageSubtitle(customViewId && viewItem ? viewItem.name : '');
|
||||
}, [customViewId]);
|
||||
}, [customViewId, viewItem, changePageSubtitle, setTopbarEditView]);
|
||||
|
||||
// Handle click a new view tab.
|
||||
const handleClickNewView = () => {
|
||||
const handleClickNewView = useCallback(() => {
|
||||
setTopbarEditView(null);
|
||||
history.push('/custom_views/accounts/new');
|
||||
};
|
||||
}, [setTopbarEditView]);
|
||||
|
||||
const handleTabChange = (viewId) => {
|
||||
const handleTabChange = useCallback((viewId) => {
|
||||
changeAccountsCurrentView(viewId || -1);
|
||||
// addAccountsTableQueries({
|
||||
// custom_view_id: viewId || null,
|
||||
// });
|
||||
};
|
||||
}, [changeAccountsCurrentView]);
|
||||
|
||||
const tabs = accountsViews.map((view) => ({
|
||||
const tabs = useMemo(() => accountsViews.map((view) => ({
|
||||
...pick(view, ['name', 'id']),
|
||||
}));
|
||||
})), [accountsViews]);;
|
||||
|
||||
return (
|
||||
<Navbar className="navbar--dashboard-views">
|
||||
<NavbarGroup align={Alignment.LEFT}>
|
||||
<DashboardViewsTabs
|
||||
defaultTabText={'All Accounts'}
|
||||
initialViewId={customViewId}
|
||||
resourceName={'accounts'}
|
||||
onChange={handleTabChange}
|
||||
@@ -72,8 +68,10 @@ function AccountsViewsTabs({
|
||||
);
|
||||
}
|
||||
|
||||
const AccountsViewsTabsMemo = memo(AccountsViewsTabs);
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
viewId: ownProps.match.params.custom_view_id,
|
||||
viewId: -1,
|
||||
});
|
||||
|
||||
const withAccountsViewsTabs = connect(mapStateToProps);
|
||||
@@ -87,4 +85,4 @@ export default compose(
|
||||
})),
|
||||
withAccountsTableActions,
|
||||
withViewDetail(),
|
||||
)(AccountsViewsTabs);
|
||||
)(AccountsViewsTabsMemo);
|
||||
|
||||
@@ -3,15 +3,76 @@ import {
|
||||
Position,
|
||||
Classes,
|
||||
Tooltip,
|
||||
MenuItem,
|
||||
Menu,
|
||||
MenuDivider,
|
||||
Intent
|
||||
} from '@blueprintjs/core';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { Icon, Money, If, Choose } from 'components';
|
||||
import { Icon, Money, If } from 'components';
|
||||
import { saveInvoke } from 'utils';
|
||||
import { formatMessage } from 'services/intl';
|
||||
import { POPOVER_CONTENT_SIZING } from '@blueprintjs/core/lib/esm/common/classes';
|
||||
|
||||
export function AccountActionsMenuList({
|
||||
account,
|
||||
|
||||
onNewChildAccount,
|
||||
onEditAccount,
|
||||
onActivateAccount,
|
||||
onInactivateAccount,
|
||||
onDeleteAccount,
|
||||
}) {
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={<Icon icon="reader-18" />}
|
||||
text={formatMessage({ id: 'view_details' })}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={formatMessage({ id: 'edit_account' })}
|
||||
onClick={() => saveInvoke(onEditAccount, account)}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={<Icon icon="plus" />}
|
||||
text={formatMessage({ id: 'new_child_account' })}
|
||||
onClick={() => saveInvoke(onNewChildAccount, account)}
|
||||
/>
|
||||
<MenuDivider />
|
||||
<If condition={account.active}>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'inactivate_account' })}
|
||||
icon={<Icon icon="pause-16" iconSize={16} />}
|
||||
onClick={() => saveInvoke(onInactivateAccount, account)}
|
||||
/>
|
||||
</If>
|
||||
<If condition={!account.active}>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'activate_account' })}
|
||||
icon={<Icon icon="play-16" iconSize={16} />}
|
||||
onClick={() => saveInvoke(onActivateAccount, account)}
|
||||
/>
|
||||
</If>
|
||||
<MenuItem
|
||||
text={formatMessage({ id: 'delete_account' })}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
intent={Intent.DANGER}
|
||||
onClick={() => saveInvoke(onDeleteAccount, account)}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
export function NormalCell({ cell: { value } }) {
|
||||
const { formatMessage } = useIntl();
|
||||
const arrowDirection = value === 'credit' ? 'down' : 'up';
|
||||
|
||||
// if (value !== 'credit' || value !== 'debit') {
|
||||
// return '';
|
||||
// }
|
||||
return (
|
||||
<Tooltip
|
||||
className={Classes.TOOLTIP_INDICATOR}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { If } from 'components';
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { If, AppToaster } from 'components';
|
||||
import { formatMessage } from 'services/intl';
|
||||
|
||||
export const accountNameAccessor = (account) => {
|
||||
return (
|
||||
@@ -11,3 +13,23 @@ export const accountNameAccessor = (account) => {
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
// Handle delete errors in bulk and singular.
|
||||
export const handleDeleteErrors = (errors) => {
|
||||
if (errors.find((e) => e.type === 'ACCOUNT.PREDEFINED')) {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'you_could_not_delete_predefined_accounts',
|
||||
}),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
if (errors.find((e) => e.type === 'ACCOUNT.HAS.ASSOCIATED.TRANSACTIONS')) {
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'cannot_delete_account_has_associated_transactions',
|
||||
}),
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -18,6 +18,7 @@ export default (mapState) => {
|
||||
accountsTableQuery: state.accounts.tableQuery,
|
||||
accountsLoading: state.accounts.loading,
|
||||
accountErrors: state.accounts.errors,
|
||||
accountsSelectedRows: state.accounts.selectedRows,
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
import t from 'store/types';
|
||||
import { fetchAccountsTable } from 'store/accounts/accounts.actions';
|
||||
import { fetchAccountsTable, setBulkAction } from 'store/accounts/accounts.actions';
|
||||
|
||||
const mapActionsToProps = (dispatch) => ({
|
||||
requestFetchAccountsTable: (query = {}) =>
|
||||
@@ -21,11 +21,12 @@ const mapActionsToProps = (dispatch) => ({
|
||||
type: t.ACCOUNTS_TABLE_QUERIES_ADD,
|
||||
queries,
|
||||
}),
|
||||
setSelectedRowsAccounts: (ids) =>
|
||||
setSelectedRowsAccounts: (selectedRows) =>
|
||||
dispatch({
|
||||
type: t.ACCOUNTS_SELECTED_ROWS_SET,
|
||||
payload: { ids },
|
||||
payload: { selectedRows },
|
||||
}),
|
||||
setAccountsBulkAction: (actionName) => setBulkAction(actionName),
|
||||
});
|
||||
|
||||
export default connect(null, mapActionsToProps);
|
||||
|
||||
13
client/src/containers/Alert/withAlertActions.js
Normal file
13
client/src/containers/Alert/withAlertActions.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { connect } from 'react-redux';
|
||||
import t from 'store/types';
|
||||
|
||||
export const mapStateToProps = (state, props) => {
|
||||
return {};
|
||||
};
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
openAlert: (name, payload) => dispatch({ type: t.OPEN_ALERT, name, payload }),
|
||||
closeAlert: (name, payload) => dispatch({ type: t.CLOSE_ALERT, name, payload }),
|
||||
});
|
||||
|
||||
export default connect(null, mapDispatchToProps);
|
||||
19
client/src/containers/Alert/withAlertStoreConnect.js
Normal file
19
client/src/containers/Alert/withAlertStoreConnect.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
isAlertOpenFactory,
|
||||
getAlertPayloadFactory,
|
||||
} from 'store/dashboard/dashboard.selectors';
|
||||
|
||||
export default (mapState) => {
|
||||
const isAlertOpen = isAlertOpenFactory();
|
||||
const getAlertPayload = getAlertPayloadFactory();
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const mapped = {
|
||||
isOpen: isAlertOpen(state, props),
|
||||
payload: getAlertPayload(state, props),
|
||||
};
|
||||
return mapState ? mapState(mapped) : mapped;
|
||||
};
|
||||
return connect(mapStateToProps);
|
||||
}
|
||||
74
client/src/containers/Alerts/AccountActivateAlert.js
Normal file
74
client/src/containers/Alerts/AccountActivateAlert.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
useIntl,
|
||||
} from 'react-intl';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Account activate alert.
|
||||
*/
|
||||
function AccountActivateAlert({
|
||||
name,
|
||||
isOpen,
|
||||
payload: { accountId },
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert,
|
||||
|
||||
requestActivateAccount
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
// Handle alert cancel.
|
||||
const handleCancel = () => {
|
||||
closeAlert('account-activate');
|
||||
};
|
||||
|
||||
// Handle activate account confirm.
|
||||
const handleConfirmAccountActivate = () => {
|
||||
requestActivateAccount(accountId)
|
||||
.then(() => {
|
||||
closeAlert('account-activate');
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_account_has_been_successfully_activated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((error) => {
|
||||
closeAlert('account-activate');
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'activate'} />}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancel}
|
||||
onConfirm={handleConfirmAccountActivate}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_activate_this_account'} />
|
||||
</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
withAccountsActions
|
||||
)(AccountActivateAlert);
|
||||
76
client/src/containers/Alerts/AccountBulkActivateAlert.js
Normal file
76
client/src/containers/Alerts/AccountBulkActivateAlert.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
FormattedHTMLMessage,
|
||||
useIntl
|
||||
} from 'react-intl';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
function AccountBulkActivateAlert({
|
||||
name,
|
||||
isOpen,
|
||||
payload: { accountsIds },
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert,
|
||||
|
||||
requestBulkActivateAccounts
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const selectedRowsCount = 0;
|
||||
|
||||
// Handle alert cancel.
|
||||
const handleClose = () => {
|
||||
closeAlert(name);
|
||||
}
|
||||
|
||||
// Handle Bulk activate account confirm.
|
||||
const handleConfirmBulkActivate = () => {
|
||||
requestBulkActivateAccounts(accountsIds)
|
||||
.then(() => {
|
||||
closeAlert(name);
|
||||
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_accounts_has_been_successfully_activated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
closeAlert(name);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={`${formatMessage({
|
||||
id: 'activate',
|
||||
})} (${selectedRowsCount})`}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleClose}
|
||||
onConfirm={handleConfirmBulkActivate}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_activate_this_accounts'} />
|
||||
</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
withAccountsActions
|
||||
)(AccountBulkActivateAlert);
|
||||
80
client/src/containers/Alerts/AccountBulkDeleteAlert.js
Normal file
80
client/src/containers/Alerts/AccountBulkDeleteAlert.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
useIntl
|
||||
} from 'react-intl';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import { handleDeleteErrors } from 'containers/Accounts/utils';
|
||||
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
function AccountBulkDeleteAlert({
|
||||
// #ownProps
|
||||
name,
|
||||
|
||||
// #withAlertStoreConnect
|
||||
isOpen,
|
||||
payload: { accountsIds },
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert,
|
||||
|
||||
// #withAccountsActions
|
||||
requestDeleteBulkAccounts
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const selectedRowsCount = 0;
|
||||
|
||||
const handleCancel = () => {
|
||||
closeAlert(name);
|
||||
};
|
||||
// Handle confirm accounts bulk delete.
|
||||
const handleConfirmBulkDelete = () => {
|
||||
requestDeleteBulkAccounts(accountsIds)
|
||||
.then(() => {
|
||||
closeAlert(name);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_accounts_has_been_successfully_deleted',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
closeAlert(name);
|
||||
handleDeleteErrors(errors);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={`${formatMessage({
|
||||
id: 'delete',
|
||||
})} (${selectedRowsCount})`}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancel}
|
||||
onConfirm={handleConfirmBulkDelete}
|
||||
>
|
||||
<p>
|
||||
<T id={'once_delete_these_accounts_you_will_not_able_restore_them'} />
|
||||
</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
withAccountsActions
|
||||
)(AccountBulkDeleteAlert);
|
||||
71
client/src/containers/Alerts/AccountBulkInactivateAlert.js
Normal file
71
client/src/containers/Alerts/AccountBulkInactivateAlert.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage as T, useIntl } from 'react-intl';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
function AccountBulkInactivateAlert({
|
||||
name,
|
||||
isOpen,
|
||||
payload: { accountsIds },
|
||||
|
||||
// #withAccountsActions
|
||||
requestBulkInactiveAccounts,
|
||||
|
||||
closeAlert,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const selectedRowsCount = 0;
|
||||
|
||||
// Handle alert cancel.
|
||||
const handleCancel = () => {
|
||||
closeAlert(name);
|
||||
};
|
||||
// Handle Bulk Inactive accounts confirm.
|
||||
const handleConfirmBulkInactive = () => {
|
||||
requestBulkInactiveAccounts(accountsIds)
|
||||
.then(() => {
|
||||
closeAlert(name);
|
||||
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_accounts_have_been_successfully_inactivated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
closeAlert(name);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={`${formatMessage({
|
||||
id: 'inactivate',
|
||||
})} (${selectedRowsCount})`}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancel}
|
||||
onConfirm={handleConfirmBulkInactive}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_inactive_this_accounts'} />
|
||||
</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
withAccountsActions,
|
||||
)(AccountBulkInactivateAlert);
|
||||
84
client/src/containers/Alerts/AccountDeleteAlert.js
Normal file
84
client/src/containers/Alerts/AccountDeleteAlert.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
FormattedHTMLMessage,
|
||||
useIntl
|
||||
} from 'react-intl';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import { handleDeleteErrors } from 'containers/Accounts/utils';
|
||||
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
/**
|
||||
* Account delete alerts.
|
||||
*/
|
||||
function AccountDeleteAlert({
|
||||
name,
|
||||
|
||||
// #withAlertStoreConnect
|
||||
isOpen,
|
||||
payload: { accountId },
|
||||
|
||||
// #withAccountsActions
|
||||
requestDeleteAccount,
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
// handle cancel delete account alert.
|
||||
const handleCancelAccountDelete = () => {
|
||||
closeAlert(name);
|
||||
};
|
||||
|
||||
// Handle confirm account delete.
|
||||
const handleConfirmAccountDelete = () => {
|
||||
requestDeleteAccount(accountId)
|
||||
.then(() => {
|
||||
closeAlert(name);
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_account_has_been_successfully_deleted',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((errors) => {
|
||||
handleDeleteErrors(errors);
|
||||
closeAlert(name);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'delete'} />}
|
||||
icon="trash"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancelAccountDelete}
|
||||
onConfirm={handleConfirmAccountDelete}
|
||||
>
|
||||
<p>
|
||||
<FormattedHTMLMessage
|
||||
id={'once_delete_this_account_you_will_able_to_restore_it'}
|
||||
/>
|
||||
</p>
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
withAccountsActions
|
||||
)(AccountDeleteAlert);
|
||||
71
client/src/containers/Alerts/AccountInactivateAlert.js
Normal file
71
client/src/containers/Alerts/AccountInactivateAlert.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
FormattedMessage as T,
|
||||
useIntl,
|
||||
} from 'react-intl';
|
||||
import { Intent, Alert } from '@blueprintjs/core';
|
||||
import { queryCache } from 'react-query';
|
||||
import { AppToaster } from 'components';
|
||||
|
||||
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||
import withAccountsActions from 'containers/Accounts/withAccountsActions';
|
||||
|
||||
import { compose } from 'utils';
|
||||
|
||||
function AccountInactivateAlert({
|
||||
name,
|
||||
isOpen,
|
||||
payload: { accountId },
|
||||
|
||||
// #withAlertActions
|
||||
closeAlert,
|
||||
|
||||
// #withAccountsActions
|
||||
requestInactiveAccount,
|
||||
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const handleCancelInactiveAccount = () => {
|
||||
closeAlert('account-inactivate');
|
||||
};
|
||||
|
||||
const handleConfirmAccountActive = () => {
|
||||
requestInactiveAccount(accountId)
|
||||
.then(() => {
|
||||
closeAlert('account-inactivate');
|
||||
AppToaster.show({
|
||||
message: formatMessage({
|
||||
id: 'the_account_has_been_successfully_inactivated',
|
||||
}),
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
})
|
||||
.catch((error) => {
|
||||
closeAlert('account-inactivate');
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Alert
|
||||
cancelButtonText={<T id={'cancel'} />}
|
||||
confirmButtonText={<T id={'inactivate'} />}
|
||||
intent={Intent.WARNING}
|
||||
isOpen={isOpen}
|
||||
onCancel={handleCancelInactiveAccount}
|
||||
onConfirm={handleConfirmAccountActive}
|
||||
>
|
||||
<p>
|
||||
<T id={'are_sure_to_inactive_this_account'} />
|
||||
</p>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
withAlertStoreConnect(),
|
||||
withAlertActions,
|
||||
withAccountsActions
|
||||
)(AccountInactivateAlert);
|
||||
5
client/src/containers/Alerts/index.js
Normal file
5
client/src/containers/Alerts/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import AccountDeleteAlert from './AccountDeleteAlert';
|
||||
|
||||
export default {
|
||||
AccountDeleteAlert,
|
||||
};
|
||||
@@ -22,7 +22,7 @@ import { transformApiErrors, transformAccountToForm } from './utils';
|
||||
import 'style/pages/Accounts/AccountFormDialog.scss';
|
||||
|
||||
const defaultInitialValues = {
|
||||
account_type_id: '',
|
||||
account_type: '',
|
||||
parent_account_id: '',
|
||||
name: '',
|
||||
code: '',
|
||||
@@ -51,7 +51,7 @@ function AccountFormDialogContent({
|
||||
accountId,
|
||||
action,
|
||||
parentAccountId,
|
||||
accountTypeId,
|
||||
accountType,
|
||||
}) {
|
||||
const { formatMessage } = useIntl();
|
||||
const isNewMode = !accountId;
|
||||
@@ -72,7 +72,10 @@ function AccountFormDialogContent({
|
||||
const handleSuccess = () => {
|
||||
closeDialog(dialogName);
|
||||
queryCache.invalidateQueries('accounts-table');
|
||||
queryCache.invalidateQueries('accounts-list');
|
||||
|
||||
setTimeout(() => {
|
||||
queryCache.invalidateQueries('accounts-list');
|
||||
}, 1000);
|
||||
|
||||
AppToaster.show({
|
||||
message: formatMessage(
|
||||
@@ -116,7 +119,7 @@ function AccountFormDialogContent({
|
||||
transformAccountToForm(account, {
|
||||
action,
|
||||
parentAccountId,
|
||||
accountTypeId,
|
||||
accountType,
|
||||
}),
|
||||
defaultInitialValues,
|
||||
),
|
||||
@@ -158,7 +161,7 @@ function AccountFormDialogContent({
|
||||
>
|
||||
<AccountFormDialogFields
|
||||
dialogName={dialogName}
|
||||
isNewMode={isNewMode}
|
||||
action={action}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
</Formik>
|
||||
|
||||
@@ -30,7 +30,7 @@ import { useAutofocus } from 'hooks';
|
||||
function AccountFormDialogFields({
|
||||
// #ownPropscl
|
||||
onClose,
|
||||
isNewMode,
|
||||
action,
|
||||
|
||||
// #withAccounts
|
||||
accounts,
|
||||
@@ -42,7 +42,7 @@ function AccountFormDialogFields({
|
||||
return (
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<FastField name={'account_type'}>
|
||||
<Field name={'account_type'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
<FormGroup
|
||||
label={<T id={'account_type'} />}
|
||||
@@ -59,13 +59,13 @@ function AccountFormDialogFields({
|
||||
onTypeSelected={(accountType) => {
|
||||
form.setFieldValue('account_type', accountType.key);
|
||||
}}
|
||||
disabled={!isNewMode}
|
||||
disabled={action === 'edit' || action === 'new_child'}
|
||||
popoverProps={{ minimal: true }}
|
||||
popoverFill={true}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</FastField>
|
||||
</Field>
|
||||
|
||||
<FastField name={'name'}>
|
||||
{({ field, meta: { error, touched } }) => (
|
||||
@@ -126,7 +126,11 @@ function AccountFormDialogFields({
|
||||
|
||||
<If condition={values.subaccount}>
|
||||
<FastField name={'parent_account_id'}>
|
||||
{({ form, field: { value }, meta: { error, touched } }) => (
|
||||
{({
|
||||
form: { values, setFieldValue },
|
||||
field: { value },
|
||||
meta: { error, touched },
|
||||
}) => (
|
||||
<FormGroup
|
||||
label={<T id={'parent_account'} />}
|
||||
className={classNames(
|
||||
@@ -139,11 +143,12 @@ function AccountFormDialogFields({
|
||||
<AccountsSelectList
|
||||
accounts={accounts}
|
||||
onAccountSelected={(account) => {
|
||||
form.setFieldValue('parent_account_id', account.id);
|
||||
setFieldValue('parent_account_id', account.id);
|
||||
}}
|
||||
defaultSelectText={<T id={'select_parent_account'} />}
|
||||
selectedAccountId={value}
|
||||
popoverFill={true}
|
||||
filterByTypes={values.account_type}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
@@ -177,7 +182,7 @@ function AccountFormDialogFields({
|
||||
style={{ minWidth: '75px' }}
|
||||
type="submit"
|
||||
>
|
||||
{!isNewMode ? <T id={'edit'} /> : <T id={'submit'} />}
|
||||
{action === 'edit' ? <T id={'edit'} /> : <T id={'submit'} />}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,7 @@ function AccountFormDialog({
|
||||
accountId={payload.id}
|
||||
action={payload.action}
|
||||
parentAccountId={payload.parentAccountId}
|
||||
accountTypeId={payload.accountTypeId}
|
||||
accountType={payload.accountType}
|
||||
/>
|
||||
</DialogSuspense>
|
||||
</Dialog>
|
||||
|
||||
@@ -14,11 +14,11 @@ export const transformApiErrors = (errors) => {
|
||||
export const transformAccountToForm = (account, {
|
||||
action,
|
||||
parentAccountId,
|
||||
accountTypeId
|
||||
accountType
|
||||
}) => {
|
||||
return {
|
||||
parent_account_id: action === 'new_child' ? parentAccountId : '',
|
||||
account_type_id: action === 'new_child'? accountTypeId : '',
|
||||
account_type: action === 'new_child'? accountType : '',
|
||||
subaccount: action === 'new_child' ? true : false,
|
||||
...account,
|
||||
}
|
||||
|
||||
6
client/src/containers/Router/withRoute.js
Normal file
6
client/src/containers/Router/withRoute.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { connect } from "react-redux";
|
||||
import { withRouter } from "react-router-dom"
|
||||
|
||||
export default (mapState) => {
|
||||
return () => withRouter ;
|
||||
};
|
||||
@@ -28,4 +28,4 @@ const mapDispatchToProps = (dispatch, props) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)
|
||||
export default connect(null, mapDispatchToProps)
|
||||
Reference in New Issue
Block a user