mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 12:20:31 +00:00
314 lines
7.8 KiB
JavaScript
314 lines
7.8 KiB
JavaScript
import React from 'react';
|
|
import { isNull, isEmpty } from 'lodash';
|
|
import { compose, curry } from 'lodash/fp';
|
|
import styled from 'styled-components';
|
|
import { Link } from 'react-router-dom';
|
|
import { ContextMenu2 } from '@blueprintjs/popover2';
|
|
import { Menu, MenuItem, MenuDivider, Intent } from '@blueprintjs/core';
|
|
import intl from 'react-intl-universal';
|
|
|
|
import {
|
|
BankAccountsList,
|
|
BankAccount,
|
|
If,
|
|
Icon,
|
|
T,
|
|
Can,
|
|
} from '../../../components';
|
|
import {
|
|
AccountAction,
|
|
CashflowAction,
|
|
AbilitySubject,
|
|
} from '../../../common/abilityOption';
|
|
|
|
import { useCashFlowAccountsContext } from './CashFlowAccountsProvider';
|
|
|
|
import withDrawerActions from '../../Drawer/withDrawerActions';
|
|
import withAlertsActions from '../../Alert/withAlertActions';
|
|
import withDialogActions from '../../Dialog/withDialogActions';
|
|
|
|
import { safeCallback } from 'utils';
|
|
import { addMoneyIn, addMoneyOut } from 'common/cashflowOptions';
|
|
|
|
const CASHFLOW_SKELETON_N = 4;
|
|
|
|
/**
|
|
* Cashflow accounts skeleton for loading state.
|
|
*/
|
|
function CashflowAccountsSkeleton() {
|
|
return [...Array(CASHFLOW_SKELETON_N)].map((e, i) => (
|
|
<BankAccount
|
|
title={'XXXXX'}
|
|
code={'XXXXX'}
|
|
balance={'XXXXXX'}
|
|
cash={'cash'}
|
|
loading={true}
|
|
/>
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Cashflow bank account.
|
|
*/
|
|
function CashflowBankAccount({
|
|
// #withAlertsDialog
|
|
openAlert,
|
|
|
|
// #withDial
|
|
openDialog,
|
|
|
|
// #withDrawerActions
|
|
openDrawer,
|
|
|
|
account,
|
|
}) {
|
|
// Handle view detail account.
|
|
const handleViewClick = () => {
|
|
openDrawer('account-drawer', { accountId: account.id });
|
|
};
|
|
// Handle delete action account.
|
|
const handleDeleteClick = () => {
|
|
openAlert('account-delete', { accountId: account.id });
|
|
};
|
|
// Handle inactivate action account.
|
|
const handleInactivateClick = () => {
|
|
openAlert('account-inactivate', { accountId: account.id });
|
|
};
|
|
// Handle activate action account.
|
|
const handleActivateClick = () => {
|
|
openAlert('account-activate', { accountId: account.id });
|
|
};
|
|
// Handle edit account action.
|
|
const handleEditAccount = () => {
|
|
openDialog('account-form', { action: 'edit', id: account.id });
|
|
};
|
|
// Handle money in menu item actions.
|
|
const handleMoneyInClick = (transactionType) => {
|
|
openDialog('money-in', {
|
|
account_type: transactionType,
|
|
account_id: account.id,
|
|
});
|
|
};
|
|
// Handle money out menu item actions.
|
|
const handleMoneyOutClick = (transactionType) => {
|
|
openDialog('money-out', {
|
|
account_type: transactionType,
|
|
account_id: account.id,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<ContextMenu2
|
|
content={
|
|
<CashflowAccountContextMenu
|
|
account={account}
|
|
onViewClick={handleViewClick}
|
|
onDeleteClick={handleDeleteClick}
|
|
onActivateClick={handleActivateClick}
|
|
onInactivateClick={handleInactivateClick}
|
|
onEditClick={handleEditAccount}
|
|
onMoneyInClick={handleMoneyInClick}
|
|
onMoneyOutClick={handleMoneyOutClick}
|
|
/>
|
|
}
|
|
>
|
|
<CashflowAccountAnchor
|
|
to={`/cashflow-accounts/${account.id}/transactions`}
|
|
>
|
|
<BankAccount
|
|
title={account.name}
|
|
code={account.code}
|
|
balance={!isNull(account.amount) ? account.formatted_amount : '-'}
|
|
type={account.account_type}
|
|
updatedBeforeText={getUpdatedBeforeText(account.createdAt)}
|
|
/>
|
|
</CashflowAccountAnchor>
|
|
</ContextMenu2>
|
|
);
|
|
}
|
|
|
|
const CashflowBankAccountEnhanced = compose(
|
|
withAlertsActions,
|
|
withDrawerActions,
|
|
withDialogActions,
|
|
)(CashflowBankAccount);
|
|
|
|
function getUpdatedBeforeText(createdAt) {
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Cashflow accounts grid items.
|
|
*/
|
|
function CashflowAccountsGridItems({ accounts }) {
|
|
return accounts.map((account) => (
|
|
<CashflowBankAccountEnhanced account={account} />
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Cashflow accounts empty state.
|
|
*/
|
|
function CashflowAccountsEmptyState() {
|
|
return (
|
|
<AccountsEmptyStateBase>
|
|
<AccountsEmptyStateTitle>
|
|
<T id={'cash_flow.accounts.no_results'} />
|
|
</AccountsEmptyStateTitle>
|
|
</AccountsEmptyStateBase>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Cashflow accounts grid.
|
|
*/
|
|
export default function CashflowAccountsGrid() {
|
|
// Retrieve list context.
|
|
const { cashflowAccounts, isCashFlowAccountsLoading } =
|
|
useCashFlowAccountsContext();
|
|
|
|
return (
|
|
<CashflowAccountsGridWrap>
|
|
<BankAccountsList>
|
|
{isCashFlowAccountsLoading ? (
|
|
<CashflowAccountsSkeleton />
|
|
) : isEmpty(cashflowAccounts) ? (
|
|
<CashflowAccountsEmptyState />
|
|
) : (
|
|
<CashflowAccountsGridItems accounts={cashflowAccounts} />
|
|
)}
|
|
</BankAccountsList>
|
|
</CashflowAccountsGridWrap>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Cashflow account money out context menu.
|
|
*/
|
|
function CashflowAccountMoneyInContextMenu({ onClick }) {
|
|
const handleItemClick = curry((transactionType, event) => {
|
|
onClick && onClick(transactionType, event);
|
|
});
|
|
|
|
return addMoneyIn.map((option) => (
|
|
<MenuItem text={option.name} onClick={handleItemClick(option.value)} />
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Cashflow account money in context menu.
|
|
*/
|
|
function CashflowAccountMoneyOutContextMenu({ onClick }) {
|
|
const handleItemClick = curry((transactionType, event) => {
|
|
onClick && onClick(transactionType, event);
|
|
});
|
|
|
|
return addMoneyOut.map((option) => (
|
|
<MenuItem text={option.name} onClick={handleItemClick(option.value)} />
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Cashflow account context menu.
|
|
*/
|
|
function CashflowAccountContextMenu({
|
|
account,
|
|
onViewClick,
|
|
onEditClick,
|
|
onInactivateClick,
|
|
onActivateClick,
|
|
onDeleteClick,
|
|
onMoneyInClick,
|
|
onMoneyOutClick,
|
|
}) {
|
|
return (
|
|
<Menu>
|
|
<MenuItem
|
|
icon={<Icon icon="reader-18" />}
|
|
text={intl.get('view_details')}
|
|
onClick={safeCallback(onViewClick)}
|
|
/>
|
|
<Can I={CashflowAction.Create} a={AbilitySubject.Cashflow}>
|
|
<MenuDivider />
|
|
<MenuItem
|
|
text={<T id={'cash_flow_money_in'} />}
|
|
icon={<Icon icon={'arrow-downward'} iconSize={16} />}
|
|
>
|
|
<CashflowAccountMoneyInContextMenu onClick={onMoneyInClick} />
|
|
</MenuItem>
|
|
|
|
<MenuItem
|
|
text={<T id={'cash_flow_money_out'} />}
|
|
icon={<Icon icon={'arrow-upward'} iconSize={16} />}
|
|
>
|
|
<CashflowAccountMoneyOutContextMenu onClick={onMoneyOutClick} />
|
|
</MenuItem>
|
|
</Can>
|
|
<Can I={CashflowAction.Edit} a={AbilitySubject.Cashflow}>
|
|
<MenuDivider />
|
|
|
|
<MenuItem
|
|
icon={<Icon icon="pen-18" />}
|
|
text={intl.get('edit_account')}
|
|
onClick={safeCallback(onEditClick)}
|
|
/>
|
|
</Can>
|
|
<Can I={AccountAction.Edit} a={AbilitySubject.Account}>
|
|
<MenuDivider />
|
|
<If condition={account.active}>
|
|
<MenuItem
|
|
text={intl.get('inactivate_account')}
|
|
icon={<Icon icon="pause-16" iconSize={16} />}
|
|
onClick={safeCallback(onInactivateClick)}
|
|
/>
|
|
</If>
|
|
<If condition={!account.active}>
|
|
<MenuItem
|
|
text={intl.get('activate_account')}
|
|
icon={<Icon icon="play-16" iconSize={16} />}
|
|
onClick={safeCallback(onActivateClick)}
|
|
/>
|
|
</If>
|
|
</Can>
|
|
<Can I={CashflowAction.Delete} a={AbilitySubject.Cashflow}>
|
|
<MenuDivider />
|
|
<MenuItem
|
|
text={intl.get('delete_account')}
|
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
|
intent={Intent.DANGER}
|
|
onClick={safeCallback(onDeleteClick)}
|
|
/>
|
|
</Can>
|
|
</Menu>
|
|
);
|
|
}
|
|
|
|
const CashflowAccountAnchor = styled(Link)`
|
|
&,
|
|
&:hover,
|
|
&:focus,
|
|
&:active {
|
|
color: inherit;
|
|
text-decoration: none;
|
|
}
|
|
`;
|
|
|
|
const CashflowAccountsGridWrap = styled.div`
|
|
margin: 30px;
|
|
`;
|
|
|
|
const CashflowBankAccountWrap = styled.div``;
|
|
|
|
const AccountsEmptyStateBase = styled.div`
|
|
flex: 1;
|
|
text-align: center;
|
|
margin: 2rem 0;
|
|
`;
|
|
const AccountsEmptyStateTitle = styled.h1`
|
|
font-size: 16px;
|
|
color: #626b76;
|
|
opacity: 0.8;
|
|
line-height: 1.6;
|
|
font-weight: 500;
|
|
`;
|